从零开始封装自己的自定义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 相关文章推荐
jQuery页面滚动浮动层智能定位实例代码
Aug 23 Javascript
jQuery之过滤元素操作小结
Nov 30 Javascript
原生javaScript做得动态表格(注释写的很清楚)
Dec 29 Javascript
谈谈JSON对象和字符串之间的相互转换JSON.stringify(obj)和JSON.parse(string)
Oct 01 Javascript
jQuery添加删除DOM元素方法详解
Jan 18 Javascript
jquery操作select元素和option的实例代码
Feb 03 Javascript
jQuery给表格添加分页效果
Mar 02 Javascript
jquery dataTable 后台加载数据并分页实例代码
Jun 07 jQuery
Node.js 使用axios读写influxDB的方法示例
Oct 26 Javascript
微信小程序如何连接Java后台
Aug 08 Javascript
微信小程序3D轮播实现代码
Sep 19 Javascript
vue打开新窗口并实现传参的图文实例
Mar 04 Vue.js
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
如何在PHP中使用Oracle数据库(2)
2006/10/09 PHP
php在线打包程序源码
2008/07/27 PHP
PHP 实用代码收集
2010/01/22 PHP
php使HTML标签自动补全闭合函数代码
2012/10/04 PHP
php5.5新数组函数array_column使用
2013/07/08 PHP
Yii框架实现的验证码、登录及退出功能示例
2017/05/20 PHP
PHP基于mcript扩展实现对称加密功能示例
2019/02/21 PHP
jQuery1.4.2与老版本json格式兼容的解决方法
2011/02/12 Javascript
jquery中使用ajax获取远程页面信息
2011/11/13 Javascript
浅析JQuery UI Dialog的样式设置问题
2013/12/18 Javascript
JavaScript实现类似拉勾网的鼠标移入移出效果
2016/10/27 Javascript
对存在JavaScript隐式类型转换的四种情况的总结(必看篇)
2017/08/31 Javascript
vuejs实现递归树型菜单组件
2018/01/13 Javascript
element-ui 表格实现单元格可编辑的示例
2018/02/26 Javascript
Node.JS段点续传:Nginx配置文件分段下载功能的实现方法
2018/03/12 Javascript
react 应用多入口配置及实践总结
2018/10/17 Javascript
webpack 开发和生产并行设置的方法
2018/11/08 Javascript
Jquery cookie插件实现原理代码解析
2020/08/04 jQuery
Vue+scss白天和夜间模式切换功能的实现方法
2021/01/05 Vue.js
通过python下载FTP上的文件夹的实现代码
2013/02/10 Python
30分钟搭建Python的Flask框架并在上面编写第一个应用
2015/03/30 Python
Python当中的array数组对象实例详解
2019/06/12 Python
django ModelForm修改显示缩略图 imagefield类型的实例
2019/07/28 Python
python编写微信公众号首图思路详解
2019/12/13 Python
Python 按比例获取样本数据或执行任务的实现代码
2020/12/03 Python
python 装饰器的基本使用
2021/01/13 Python
ebookers英国:隶属全球最大的在线旅游公司Expedia
2017/12/28 全球购物
英国HYPE双肩包官网:英国本土时尚潮牌
2018/09/26 全球购物
实习生求职自荐信
2014/02/07 职场文书
银行批评与自我批评
2014/02/10 职场文书
房屋买卖委托公证书
2014/04/08 职场文书
机械专业毕业生自我鉴定2014
2014/10/04 职场文书
外贸采购员岗位职责
2015/04/03 职场文书
2015入党个人自传范文
2015/06/26 职场文书
中小学教师继续教育心得体会
2016/01/19 职场文书
《少年闰土》教学反思
2016/02/18 职场文书