从零开始封装自己的自定义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 相关文章推荐
javascript cookie操作类的实现代码小结附使用方法
Jun 02 Javascript
javascript是怎么继承的介绍
Jan 05 Javascript
JQuery在页面中添加和除移DOM示例代码
Jun 24 Javascript
文本框只能选择数据到文本框禁止手动输入
Nov 22 Javascript
JavaScript按位运算符的应用简析
Feb 04 Javascript
JS实现很实用的对联广告代码(可自适应高度)
Sep 18 Javascript
10个很棒的jQuery代码片段
Sep 24 Javascript
JS实现随机颜色的3种方法与颜色格式的转化
Jan 05 Javascript
jQueryeasyui 中如何使用datetimebox 取两个日期间相隔的天数
Jun 13 jQuery
mui框架移动开发初体验详解
Oct 11 Javascript
你不可不知的Vue.js列表渲染详解
Oct 01 Javascript
用JS实现选项卡
Mar 23 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
PHP CKEditor 上传图片实现代码
2009/11/06 PHP
PHP获取IP地址所在地信息的实例(使用纯真IP数据库qqwry.dat)
2016/11/15 PHP
Laravel6.18.19如何优雅的切换发件账户
2020/06/14 PHP
js split 的用法和定义 js split分割字符串成数组的实例代码
2012/05/13 Javascript
DWZ table的原生分页浅谈
2013/03/01 Javascript
利用javascript数组长度循环数组内所有元素
2013/12/27 Javascript
jquery根据td给相同tr下其他td赋值的实现方法
2016/10/05 Javascript
微信小程序 swiper制作tab切换实现附源码
2017/01/21 Javascript
原生js封装的ajax方法示例
2018/08/02 Javascript
[jQuery] 事件和动画详解
2019/03/05 jQuery
使用vue脚手架(vue-cli)搭建一个项目详解
2019/05/09 Javascript
微信小程序开发之map地图组件定位并手动修改位置偏差
2019/08/17 Javascript
vue el-table实现行内编辑功能
2019/12/11 Javascript
基于jsbarcode 生成条形码并将生成的条码保存至本地+源码
2020/04/27 Javascript
vue iview实现动态新增和删除
2020/06/17 Javascript
JavaScript文档加载模式以及元素获取
2020/07/28 Javascript
vue Cli 环境删除与重装教程 - 版本文档
2020/09/11 Javascript
elementUI同一页面展示多个Dialog的实现
2020/11/19 Javascript
matplotlib设置legend图例代码示例
2017/12/19 Python
Python基于OpenCV实现视频的人脸检测
2018/01/23 Python
使用Python向C语言的链接库传递数组、结构体、指针类型的数据
2019/01/29 Python
Python根据成绩分析系统浅析
2019/02/11 Python
详解Python的三种可变参数
2019/05/08 Python
python networkx 根据图的权重画图实现
2019/07/10 Python
python集合的创建、添加及删除操作示例
2019/10/08 Python
python json.dumps中文乱码问题解决
2020/04/01 Python
Python使用Opencv实现边缘检测以及轮廓检测的实现
2020/12/31 Python
Python实现图片指定位置加图片水印(附Pyinstaller打包exe)
2021/03/04 Python
在数据文件自动增长时,自动增长是否会阻塞对文件的更新
2014/05/01 面试题
体育专业个人的求职信范文
2013/09/21 职场文书
小学数学教学反思
2014/02/02 职场文书
企业元宵节主持词
2014/03/25 职场文书
股权转让协议书范本
2014/04/12 职场文书
灰雀教学反思
2014/04/28 职场文书
关于青春的演讲稿三分钟
2014/08/22 职场文书
高中化学教学反思
2016/02/22 职场文书