从零开始封装自己的自定义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 获取页面元素的位置的代码
Sep 25 Javascript
Javascript继承(上)——对象构建介绍
Nov 08 Javascript
jquery设置text的值示例(设置文本框 DIV 表单值)
Jan 06 Javascript
javascript面向对象之对象的深入理解
Jan 13 Javascript
EasyUI实现第二层弹出框的方法
Mar 01 Javascript
JS实现点击上移下移LI行数据的方法
Aug 05 Javascript
js简单判断移动端系统的方法
Feb 25 Javascript
js设置和获取自定义属性的方法
Oct 20 Javascript
JS中Attr的用法详解
Oct 09 Javascript
JS实现的透明度渐变动画效果示例
Apr 28 Javascript
在AngularJs中设置请求头信息(headers)的方法及不同方法的比较
Sep 04 Javascript
javascript使用正则表达式实现注册登入校验
Sep 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学习之 数组声明
2011/06/09 PHP
PHP实现的封装验证码类详解
2013/06/18 PHP
php阻止页面后退的方法分享
2014/02/17 PHP
javascript 触发事件列表 比较不错
2009/09/03 Javascript
修改好的jquery滚动字幕效果实现代码
2011/06/22 Javascript
Js 冒泡事件阻止实现代码
2013/01/27 Javascript
jQuery中height()方法用法实例
2014/12/24 Javascript
使用struts2+Ajax+jquery验证用户名是否已被注册
2016/03/22 Javascript
详解jQuery中的deferred对象的使用(一)
2016/05/27 Javascript
前端构建工具之gulp的配置与搭建详解
2017/06/12 Javascript
JavaScript+HTML5实现的日期比较功能示例
2017/07/12 Javascript
react路由配置方式详解
2017/08/07 Javascript
Angular实现预加载延迟模块的示例
2017/10/12 Javascript
JS实现自定义状态栏动画文字效果示例
2017/10/12 Javascript
vue 中directive功能的简单实现
2018/01/05 Javascript
vue实现word,pdf文件的导出功能
2018/07/31 Javascript
Vue-Cli 3.0 中配置高德地图的两种方式
2019/06/19 Javascript
[38:30]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第一场2
2014/05/24 DOTA
[03:34]2014DOTA2西雅图国际邀请赛 淘汰赛7月15日TOPPLAY
2014/07/15 DOTA
[44:33]EG vs Liquid 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
Python中使用装饰器时需要注意的一些问题
2015/05/11 Python
Django Web开发中django-debug-toolbar的配置以及使用
2018/05/06 Python
python MNIST手写识别数据调用API的方法
2018/08/08 Python
pandas数据筛选和csv操作的实现方法
2019/07/02 Python
flask应用部署到服务器的方法
2019/07/12 Python
Python requests模块cookie实例解析
2020/04/14 Python
Python爬虫+Tkinter制作一个翻译软件的示例
2021/02/20 Python
Python的collections模块真的很好用
2021/03/01 Python
世界著名的顶级牛排:Omaha Steak(奥马哈牛排)
2016/09/20 全球购物
李维斯牛仔裤荷兰官方网站:Levi’s NL
2020/08/23 全球购物
【魔兽争霸3重制版】原版画面与淬火MOD画面对比
2021/03/26 魔兽争霸
高中物理教学反思
2014/02/08 职场文书
社团活动总结模板
2014/06/30 职场文书
同学聚会通知书
2015/04/20 职场文书
ORACLE数据库对long类型字段进行模糊匹配的解决思路
2021/04/07 Oracle
Android中的Launch Mode详情
2022/06/05 Java/Android