从零开始封装自己的自定义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 相关文章推荐
slice函数的用法 之不错的应用
Dec 29 Javascript
Jquery选中或取消radio示例
Sep 29 Javascript
javascript中使用正则计算中文长度的例子
Apr 29 Javascript
纯javascript判断查询日期是否为有效日期
Aug 24 Javascript
详解Angular开发中的登陆与身份验证
Jul 27 Javascript
JavaScript获取服务器时间的方法详解
Dec 11 Javascript
整理关于Bootstrap模态弹出框的慕课笔记
Mar 29 Javascript
Angular5中调用第三方js插件的方法
Feb 26 Javascript
vue使用rem实现 移动端屏幕适配
Sep 26 Javascript
微信小程序实现卡片左右滑动效果的示例代码
May 01 Javascript
java和js实现的洗牌小程序
Sep 30 Javascript
如何检测JavaScript中的死循环示例详解
Aug 30 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在项目中寻找代码的坏味道(综艺命名)
2012/07/19 PHP
记录PHP错误日志 display_errors与log_errors的区别
2012/10/09 PHP
深入掌握include_once与require_once的区别
2013/06/17 PHP
在Mac OS上自行编译安装Apache服务器和PHP解释器
2015/12/24 PHP
php 实现一个字符串加密解密的函数实例代码
2016/11/01 PHP
PHP编程获取各个时间段具体时间的方法
2017/05/26 PHP
php中的explode()函数实例介绍
2019/01/18 PHP
Javascript this指针
2009/07/30 Javascript
javascript options属性集合操作代码
2009/12/28 Javascript
读jQuery之十 事件模块概述
2011/06/27 Javascript
获取服务器传来的数据 用JS去空格的正则表达式
2012/03/26 Javascript
javascript实现日期格式转换
2014/12/16 Javascript
JavaScript中判断两个字符串是否相等的方法
2015/07/07 Javascript
jQuery实现左侧导航模块的显示与隐藏效果
2016/07/04 Javascript
jQuery的ajax下载blob文件
2016/07/21 Javascript
js插件Jcrop自定义截取图片功能
2016/10/14 Javascript
JavaScript中绑定事件的三种方式及去除绑定
2016/11/05 Javascript
浅谈vue-router2路由参数注意的问题
2017/11/08 Javascript
基于纯JS实现多张图片的懒加载Lazy过程解析
2019/10/14 Javascript
使用vue实现HTML页面生成图片的方法
2020/03/12 Javascript
JS如何监听div的resize事件详解
2020/12/03 Javascript
python小技巧之批量抓取美女图片
2014/06/06 Python
关于Python中的向量相加和numpy中的向量相加效率对比
2019/08/26 Python
Python3 元组tuple入门基础
2020/02/09 Python
浅谈pycharm导入pandas包遇到的问题及解决
2020/06/01 Python
Python3.9新特性详解
2020/10/10 Python
HTML5移动端开发遇见的东西
2019/10/11 HTML / CSS
泰国汽车、火车和轮渡票预订网站:Bus Online Ticket
2017/09/09 全球购物
英国礼品和生活方式品牌:Treat Republic
2020/11/21 全球购物
怎样让char类型的东西转换成int类型
2013/12/09 面试题
中专生自我鉴定书范文
2013/12/28 职场文书
公休请假条
2014/04/11 职场文书
销售行政专员岗位职责
2014/06/10 职场文书
井冈山红色之旅感想
2014/10/07 职场文书
2015年销售工作总结范文
2015/03/30 职场文书
《老人与海鸥》教学反思
2016/02/16 职场文书