从零开始封装自己的自定义Vue组件


Posted in Javascript onOctober 09, 2018

想要封装好一个自己的vue组件,一定要熟练掌握这三个技能

父组件 —> 子组件传值(props)

子组件 —> 父组件传值($emit)

以及插槽(slot)

对于一个独立的组件来说

props是用来为组件内部注入核心的内容;

$emit用来使这个独立的组件通过一些逻辑来融入其他组件中。

举个具体点的例子,假如你要做一辆车,车轮是要封装的一个独立组件,props指的就是根据整个车的外形你可以给轮子设置一些你想要的且符合车风格的花纹,图案等;

而$emit的作用则是让这些轮子能够和整辆车完美契合的运作起来。差不多就是这个意思

下面来看代码。

首先,我们先完成div的模拟代码

<template>
<div class="selectWrap">
 <div class="select-wrapper">
  <div class="select" @click = "triggerOption">
   <div class="select-content">{{selectContent.text}}</div>
   <div class="triangle-wrapper">
    <div id="triangle-down"></div>
   </div>
  </div>
  <div class="option-wrapper" style="display: none;">
   <div class="option-item" v-for = "(item,index) in subject" :key="index" @mouseout="out($event)" @mouseover="move($event)" @click = "choose(item)">{{item.text}}</div>
  </div>
 </div>
</div>
</template>
<script>
 export default{
  data(){   return{    selectContent:{value:0,text:"小张"}, //模拟select默认选中的值
    subject:[{value:0,text:"小张"},{value:1,text:"小李"}, //模拟option中的文本和value值
         {value:2,text:"小王"},{value:4,text:"小明"}], 
   }
  },
  computed:{
   optionWrapper(){    return document.querySelector(".option-wrapper");
   },
   selectCon(){    return document.querySelector(".select-content");
   },
   subjectList(){    return document.getElementsByClassName("option-item");
   },
  },
  methods:{
   move(event){ //模拟hover效果    for(var item of this.subjectList){
     item.classList.remove("hover");
    }
    event.currentTarget.classList.add("hover");
   },
   out(event){
    event.currentTarget.classList.remove("hover");
   },
   triggerOption(){ //控制option的展示,以及选中后的高亮效果    if (this.optionWrapper.style.display == "none") {     this.optionWrapper.style.display = "block";
    }else{     this.optionWrapper.style.display = "none";
    }    for(var item of this.subjectList){     if (item.innerHTML == this.selectContent.text) {
      item.classList.add("hover");
     }else{
      item.classList.remove("hover");
     }
    }
   },   choose(item){ //选中“option”    this.selectContent.text = item.text;
    this.optionWrapper.style.display = "none";
   }
  },
 }</script>
<style>
 .selectWrap{ /*select的宽度*/
  width: 100px;
 }
 .select{
  position: relative;
  overflow: hidden;
  padding-right: 10px;
  min-width: 80px;
  width: 100%;
  height: 20px;
  line-height: 20px;
  border: 1px solid #000;
  cursor: default;
  font-size: 13px;
 }
 .select-content{
  text-align: left;
 }
 .triangle-wrapper{
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 20px;
  background-color: #fff;
  cursor: default;
 }
 #triangle-down{
  position: absolute;
  right: 5px;
  top: 50%;
  transform: translateY(-50%);
  width: 0;
  height: 0;
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  border-top: 6px solid #000;
 }
 .option-wrapper{
  position: relative;
  overflow: hidden;
  min-width: 80px;
  width: 100%;
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
  border-left: 1px solid #000;
 }
 .option-item{
  min-width: 80px;
  height: 20px;
  line-height: 20px;
  padding-right: 10px;
  text-align: left;
  cursor: default; 
 }
 .hover{
  background-color: rgb(30,144,255);
  color:#fff !important;
 }</style>

事实上,当你完成这段代码时,就已经完成了这一个组件。放到平时,我可能就直接把这段代码放到业务代码里直接用了。但既然是封装组件,我们肯定要把它抽出来了。首先我们先要思考一下,如果我们需要把这个组件抽出来,有哪些值需要父组件提供给我们呢?

相信大家一眼就能看出来,subject和selectContent这两个data是需要父组件通过props传进来的。但还有别的吗?作为一个select,父组件如果只能控制内容是不是管的有点太少了?可不可以让父组件来管理select的宽度?高度?字体大小样式等等?答案是肯定的。父组件传的值越多,子组件的耦合就越低。下面,我们对代码进行微调

<template>
 ......</template>
<script>
 export default{  props:["subject","selectContet","selectWidth”],
  mounted(){   document.querySelector(".selectWrap").style.width = 
   this.selectWidth+"px";
  },
  computed:{
   optionWrapper(){    return document.querySelector(".option-wrapper");
   },
   selectCon(){    return document.querySelector(".select-content");
   },
   subjectList(){    return document.getElementsByClassName("option-item");
   },
  },
  methods:{
   ......
   choose(item){    this.selectContent.text = item.text;    this.optionWrapper.style.display = "none";
   }
  },
 }</script>
<style> /*.selectWrap{
  width: 100px;
 }*/
 ....... </style>
 

我们通过props将之前的subject和selectContent从父组件传了进来。同时,我们还将select的宽度传了进来,并通过mounted来设置宽度。这样,父组件就能控制子组件的内容和一些简单的样式了。

当然,作为一个完善的组件,我们还需要为组件设置默认值,这样就算父组件不传值,我们的这个组件一样可以使用

<template>
 ......</template>
<script>
 export default{  props:{
   selectWidth:{
    type:Number,    default:100,
   },
   subject:{
    type:Array,
    default:function(){
     return []
    }
   },
   selectContent:{
    type:Object,
    default:function(){
     return {value:0,text:"请选择"}
    }
   },
  },
  mounted(){
   document.querySelector(".selectWrap").style.width = this.selectWidth+"px";
  },
  ...... 
  methods:{
   ......
   choose(item){    this.selectContent.text = item.text;    this.optionWrapper.style.display = "none";
   }
  },
 }</script>
<style>
 ......</style>

这回我们将props用对象的方式声明,并设置了默认值(default),假如父组件没有设置子组件的宽度,那么我们可以使用默认的100px。这样,我们的组件更加的完善!当然,我们的组件还有一个关键的功能没有实现,就是把选中的值传回给父组件,不然的话这个组件就没有意义了,我们来看choose这个函数

choose(item,value){
  this.selectContent.text = item.text;
  this.optionWrapper.style.display = "none";
  this.$emit("changeSelect",this.selectContent.text,this.selectContent.value);
}

 这样,我们就可以把选到的文本和value值传给父组件了。

当然,这仅仅是一个开头,字体大小等内容我还没有设置,不过这个组件现在已经完全可以拿出去用了

以上是vue自定义组件封装的简单实例,大家可以研究下

Javascript 相关文章推荐
node.js中的fs.fchmod方法使用说明
Dec 16 Javascript
js实现滑动触屏事件监听的方法
May 05 Javascript
详解如何在Vue2中实现组件props双向绑定
Mar 29 Javascript
JS匹配日期和时间的正则表达式示例
May 12 Javascript
微信小程序 新建登录页并实现tabBar隐藏
Jun 13 Javascript
jQuery实现点击下拉框中的值累加到文本框中的方法示例
Oct 28 jQuery
Angular2.0实现modal对话框的方法示例
Feb 18 Javascript
vue使用jsonp抓取qq音乐数据的方法
Jun 21 Javascript
jQuery实现炫丽的3d旋转星空效果
Jul 04 jQuery
node实现简单的增删改查接口实例代码
Aug 22 Javascript
layui添加动态菜单与选项卡 AJAX请求的例子
Sep 25 Javascript
适合前端Vue开发童鞋的跨平台Weex的使用详解
Oct 16 Javascript
vue axios 简单封装以及思考
Oct 09 #Javascript
angularJS实现不同视图同步刷新详解
Oct 09 #Javascript
对angular 实时更新模板视图的方法$apply详解
Oct 09 #Javascript
AngularJs返回前一页面时刷新一次前面页面的方法
Oct 09 #Javascript
详解js模板引擎art template数组渲染的方法
Oct 09 #Javascript
angular4强制刷新视图的方法
Oct 09 #Javascript
Angular4.x Event (DOM事件和自定义事件详解)
Oct 09 #Javascript
You might like
ADODB结合SMARTY使用~超级强
2006/11/25 PHP
用PHP实现弹出消息提示框的两种方法
2013/12/17 PHP
Codeigniter控制器controller继承问题实例分析
2016/01/19 PHP
PHP构造函数与析构函数用法示例
2016/09/28 PHP
PHP实现表单提交数据的验证处理功能【防SQL注入和XSS攻击等】
2017/07/21 PHP
AngularJs表单验证实例详解
2016/05/30 Javascript
Angular Module声明和获取重载实例代码
2016/09/14 Javascript
jQuery实现html双向绑定功能示例
2017/10/09 jQuery
seaJs使用心得之exports与module.exports的区别实例分析
2017/10/13 Javascript
解决node-sass偶尔安装失败的方法小结
2018/12/05 Javascript
详解vue-cli项目在IE浏览器打开报错解决方法
2020/12/10 Vue.js
JS中循环遍历数组的四种方式总结
2021/01/23 Javascript
python提取页面内url列表的方法
2015/05/25 Python
浅谈python字符串方法的简单使用
2016/07/18 Python
python读取和保存视频文件
2018/04/16 Python
python实现批量解析邮件并下载附件
2018/06/19 Python
利用Django提供的ModelForm增删改数据的方法
2019/01/06 Python
python re库的正则表达式入门学习教程
2019/03/08 Python
python cv2在验证码识别中应用实例解析
2019/12/25 Python
python为什么会环境变量设置不成功
2020/06/23 Python
Python 处理日期时间的Arrow库使用
2020/08/18 Python
python 爬虫之selenium可视化爬虫的实现
2020/12/04 Python
利用Python实现学生信息管理系统的完整实例
2020/12/30 Python
一些常用的HTML5模式(pattern) 总结
2015/07/14 HTML / CSS
html5视频自动横过来自适应页面且点击播放功能的实现
2020/06/03 HTML / CSS
英国综合网上购物商城:The Hut
2018/07/03 全球购物
加热夹克:RAVEAN
2018/10/19 全球购物
应届毕业生专业个人求职自荐信格式
2013/11/20 职场文书
学校安全教育制度
2014/01/31 职场文书
2014年大学生四年规划书范文
2014/04/03 职场文书
企业形象策划方案
2014/05/29 职场文书
水利水电专业自荐信
2014/07/08 职场文书
2014年党建工作汇报材料
2014/11/02 职场文书
办公室管理规章制度
2015/08/04 职场文书
Nginx解决403 forbidden的完整步骤
2021/04/01 Servers
Spring IOC容器Bean的作用域及生命周期实例
2022/05/30 Java/Android