从零开始封装自己的自定义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 相关文章推荐
js数据验证集合、js email验证、js url验证、js长度验证、js数字验证等简单封装
May 15 Javascript
为JavaScript添加重载函数的辅助方法
Jul 04 Javascript
javascript实现rgb颜色转换成16进制格式
Jul 10 Javascript
浅析AngularJS中的指令
Mar 20 Javascript
Js获取图片原始宽高的实现代码
May 17 Javascript
JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍
May 19 Javascript
浅谈JavaScript for循环 闭包
Jun 22 Javascript
第一次接触神奇的Bootstrap表单
Jul 27 Javascript
Javascript 之封装(Package)
Sep 14 Javascript
微信小程序如何刷新当前界面的实现方法
Jun 07 Javascript
nuxt 服务器渲染动态设置 title和seo关键字的操作
Nov 05 Javascript
JavaScript实现H5接金币功能(实例代码)
Feb 22 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
全国FM电台频率大全 - 14 江西省
2020/03/11 无线电
php开发工具之vs2005图解
2008/01/12 PHP
也谈php网站在线人数统计
2008/04/09 PHP
PHP 中关于ord($str)&amp;gt;0x80的详细说明
2012/09/23 PHP
基于flush()不能按顺序输出时的解决办法
2013/06/29 PHP
PHP独立Session数据库存储操作类分享
2014/06/11 PHP
PHP PDOStatement对象bindpram()、bindvalue()和bindcolumn之间的区别
2014/11/20 PHP
Laravel路由研究之domain解决多域名问题的方法示例
2019/04/04 PHP
PHP随机生成中文段落示例【测试网站内容时使用】
2020/04/26 PHP
php7 错误处理机制修改实例分析
2020/05/25 PHP
解析dom中的children对象数组元素firstChild,lastChild的使用
2013/07/10 Javascript
判断一个变量是数组Array类型的方法
2013/09/16 Javascript
javascript检测是否联网的实现代码
2014/09/28 Javascript
让html页面不缓存js的实现方法
2014/10/31 Javascript
javascript 数组操作详解
2015/01/29 Javascript
ECMAScript6函数默认参数
2015/06/12 Javascript
js中flexible.js实现淘宝弹性布局方案
2020/06/23 Javascript
jQuery实现简单滚动动画效果
2016/04/07 Javascript
详解从Node.js的child_process模块来学习父子进程之间的通信
2017/03/27 Javascript
使用vue与jquery实时监听用户输入状态的操作代码
2017/09/19 jQuery
vue2.0 循环遍历加载不同图片的方法
2018/03/06 Javascript
vue裁切预览组件功能的实现步骤
2018/05/04 Javascript
vue实现的树形结构加多选框示例
2019/02/02 Javascript
Vue.js自定义指令学习使用详解
2019/10/19 Javascript
nodejs脚本centos开机启动实操方法
2020/03/04 NodeJs
解决vue中axios设置超时(超过5分钟)没反应的问题
2020/09/04 Javascript
python if not in 多条件判断代码
2016/09/21 Python
flask-restful使用总结
2018/12/04 Python
python 实现快速生成连续、随机字母列表
2019/11/28 Python
html5视频常用API接口的实战示例
2020/03/20 HTML / CSS
应届生体育教师自荐信
2013/10/03 职场文书
售后服务承诺书
2014/03/26 职场文书
2015年党总支工作总结
2015/05/25 职场文书
培训学校2015年度工作总结
2015/07/20 职场文书
详解Laravel框架的依赖注入功能
2021/05/27 PHP
SQL Server Agent 服务无法启动
2022/04/20 SQL Server