从零开始封装自己的自定义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 相关文章推荐
放弃用你的InnerHTML来输出HTML吧 jQuery Tmpl不详细讲解
Apr 20 Javascript
iframe的父子窗口之间的对象相互调用基本用法
Sep 03 Javascript
js转义字符介绍
Nov 05 Javascript
深入理解Javascript中的循环优化
Nov 09 Javascript
jQuery中end()方法用法实例
Jan 08 Javascript
关于JS中二维数组的声明方法
Sep 24 Javascript
关于layui导航栏不展示下拉列表的解决方法
Sep 25 Javascript
vue自定义指令实现仅支持输入数字和浮点型的示例
Oct 30 Javascript
vue学习之Vue-Router用法实例分析
Jan 06 Javascript
使用webpack搭建pixi.js开发环境
Feb 12 Javascript
精读《Vue3.0 Function API》
May 20 Javascript
vue 使用lodash实现对象数组深拷贝操作
Sep 10 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
PHP5与MySQL数据库操作常用代码 收集
2010/03/21 PHP
php设计模式 Singleton(单例模式)
2011/06/26 PHP
深入探讨:Nginx 502 Bad Gateway错误的解决方法
2013/06/03 PHP
Yii2实现ajax上传图片插件用法
2016/04/28 PHP
一个简单的php MVC留言本实例代码(必看篇)
2016/09/22 PHP
php curl 模拟登录并获取数据实例详解
2016/12/22 PHP
PHP基于Redis消息队列实现发布微博的方法
2017/05/03 PHP
php实现的二分查找算法示例
2017/06/20 PHP
poshytip 基于jquery的 插件 主要用于显示微博人的图像和鼠标提示等
2012/10/12 Javascript
JS自动缩小超出大小的图片
2012/10/12 Javascript
jQuery修改li下的样式以及li下的img的src的值的方法
2014/11/02 Javascript
jquery实现点击label的同时触发文本框点击事件的方法
2015/06/05 Javascript
设置jQueryUI DatePicker默认语言为中文
2016/06/04 Javascript
浅谈js原生拖放
2016/11/21 Javascript
浅谈Node.js:fs文件系统模块
2016/12/08 Javascript
移动端界面的适配
2017/01/11 Javascript
JavaScript实现简单生成随机颜色的方法
2017/09/21 Javascript
jQuery实现的简单前端搜索功能示例
2017/10/28 jQuery
Vue.js上传图片到阿里云OSS存储的方法示例
2018/12/13 Javascript
Python使用plotly绘制数据图表的方法
2017/07/18 Python
python实现淘宝秒杀脚本
2020/06/23 Python
Python实现爬取亚马逊数据并打印出Excel文件操作示例
2019/05/16 Python
python与C、C++混编的四种方式(小结)
2019/07/15 Python
Django的models中on_delete参数详解
2019/07/16 Python
Python Selenium 之数据驱动测试的实现
2019/08/01 Python
如何用Python来理一理红楼梦里的那些关系
2019/08/14 Python
Python爬虫 批量爬取下载抖音视频代码实例
2019/08/16 Python
对Python中 \r, \n, \r\n的彻底理解
2020/03/06 Python
Django通过json格式收集主机信息
2020/05/29 Python
使用 prometheus python 库编写自定义指标的方法(完整代码)
2020/06/29 Python
python3:excel操作之读取数据并返回字典 + 写入的案例
2020/09/01 Python
拓展培训心得体会
2014/01/04 职场文书
会计专业大学生职业生涯规划范文
2014/01/11 职场文书
超市促销活动总结
2014/07/01 职场文书
竞聘开场白方式有哪些?
2019/08/28 职场文书
读《儒林外史》有感:少一些功利,多一些真诚
2020/01/19 职场文书