Vue 如何使用props、emit实现自定义双向绑定的实现


Posted in Javascript onJune 05, 2020

下面我将使用Vue自带的属性实现简单的双向绑定。

下面的例子就是利用了父组件传给子组件(在子组件定义props属性,在父组件的子组件上绑定属性),子组件传给父组件(在子组件使用$emit()属性定义一个触发方法,在父组件上的子组件监听这个事件)。

import Vue from 'vueEsm' 

var Com = {
  name:'Com',
  props:['val'],
  template:`<input type='text' @input='handleInput'/>`,
  methods: {
    handleInput(e){
      this.$emit("input",e.target.value);
    }
  },
}

new Vue({
   el:'#app',
   data() {
     return {
       value:''
     }
   },
   components:{
    Com
   },
   template:`
   <div>
   <Com @input='post' :val='value'></Com>
   </div>
   `,
   methods:{
    post(data){
      this.value=data;
    }
   }
 })

上面这个例子,在input标签上每次输入时触发原生事件input,在这个事件上绑定了一个handleInput方法,事件每次触发都会执行方法里的$emit属性。该属性里面第一个参数可以定义一个事件名,第二个参数可以传一个参数。这里我们把每次输入的值e.target.value传进去。在父组件的子组件上监听这个事件,定义一个post方法,方法的参数就是传入的数据。然后我们在父组件的data属性里定义一个存储值的变量value。将刚才传入的参数赋给这个变量value。最后在父组件的子组件上绑定一个自定义属性,比如val。将value传给val。在子组件定义一个props属性接受这个val。

这个例子对于理解父组件与子组件传值特别重要。

下方举例说明了我的一个自定义mySelect的实现过程:

<template>
 <div class="select">
  <div class="input" @click="collapse=!collapse">
   <span v-if="currentValue">{{currentLabel||currentValue}}</span>
   <span v-else class="placeholder">{{placeholder}}</span>

   <span :class="collapse?'arrow-down':'arrow-up'"></span>
  </div>

  <div class="option-list" v-show="!collapse">
   <div class="option-item" v-for="item in data" :key="item.id" @click="chooseItem(item)">{{item[itemLabel?itemLabel:'name']}}</div>
  </div>
 </div>
</template>

<script>
 export default {
  name: "mySelect",
  props: [
   'value',
   'placeholder',
   'data',
   'itemLabel',
   'itemValue'
  ],
  data() {
   return {
    collapse: true,
    currentValue: '',
    currentLabel: '',
   }
  },
  watch: {
   value: {
    immediate: true,
    handler(value) {
     this.currentValue = value;
     this.$emit('input', value);
     this.data.forEach(item => {
      if (item[this.itemValue ? this.itemValue : 'id'] == value) {
       return this.currentLabel = item[this.itemLabel ? this.itemLabel : 'name'];
      }
     });
    }
   },
   data:{
    immediate: true,
    handler(arr) {
     if(this.value||!this.currentLabel){
      arr.forEach(item=>{
       if(item[this.itemValue ? this.itemValue : 'id'] == this.value){
        this.currentLabel = item[this.itemLabel ? this.itemLabel : 'name'];
        return;
       }
      })
     }
    }
   }
  },
  methods: {
   chooseItem(item) {
    if (this.currentValue !== item[this.itemValue ? this.itemValue : 'id']) {
     this.$emit('change',item[this.itemValue ? this.itemValue : 'id']);
    }
    this.currentValue = item[this.itemValue ? this.itemValue : 'id'];
    this.currentLabel = item[this.itemLabel ? this.itemLabel : 'name'];
    this.$emit('input', this.currentValue);
    this.collapse = true;
   }
  }
 }
</script>

<style lang="scss" scoped>
 .select {
  position: relative;

  .input {
   width: 100%;
   height: 30px;
   line-height: 30px;
   background-color: #fff;
   border: 1px solid #02b4fe;
   border-radius: 0 3px 3px 0;
   padding-left: 10px;
   color: #666;
   position: relative;
   .placeholder {
    color: #aaa;
   }
  }

  .arrow-down {
   width: 0;
   height: 0;
   border-left: 5px solid transparent;
   border-right: 5px solid transparent;
   border-top: 8px solid #02b4fe;
   position: absolute;
   right: 5px;
   top: 10px;
  }

  .arrow-up {
   width: 0;
   height: 0;
   border-left: 5px solid transparent;
   border-right: 5px solid transparent;
   border-bottom: 8px solid #02b4fe;
   position: absolute;
   right: 5px;
   top: 10px;
  }

  .option-list {
   max-height: 200px;
   overflow-y: scroll;
   position: absolute;
   top: 2rem;
   left: 0;
   z-index: 5;
   width: 100%;
   padding: 0 5px;
   font-size: 10px;
   color: #aaa;
   background-color: #fff;
   text-align: left;
   box-shadow: 0 0 5px rgba(0, 0, 0, .1);
   border: 1px solid rgb(79, 192, 232);

   .option-item {
    text-align: center;
    line-height: 1.5rem;
   }
  }
 }
</style>

如上所示,当声明了mySelect组件之后,在项目中实际使用时,就可以如下所示直接使用:

<template>
 <mySelect v-model="testValue" placeholder="请选择" :data="testArr" item-label="id"
           item-value="name"></mySelect>
</template>
<script>
  import mySelect from './mySelect'
  
  export default{
    components:{
     mySelect
    },
     data(){
      return {
         testValue:'',
         testArr:[]
       }
     },
     mounted(){
      //预置select的下拉选择基础数据,数据为对象数组,包含id和name属性
     }
}
</script>

以上就是一个简单的自定义双向绑定组件的实现,包括简单的使用过程。在vue中的自定义组件,关于props的声明时,还是尽量使用官方建议的对象方式,可以声明属性的默认值和数据类型。我这边偷懒了用的是props的字符串数组简写方式,但是这样的话对使用组件时的错误调试不利。所以,尽量不要学我偷懒噢,亲~~~

到此这篇关于Vue 如何使用props、emit实现自定义双向绑定的实现的文章就介绍到这了,更多相关Vue props、emit实现自定义双向绑定内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
深入理解JavaScript作用域和作用域链
Oct 21 Javascript
仿猪八戒网左下角的文字滚动效果
Oct 28 Javascript
jquery ajax 同步异步的执行 return值不能取得的解决方案
Jan 08 Javascript
JavaScript 高级篇之DOM文档,简单封装及调用、动态添加、删除样式(六)
Apr 07 Javascript
Json对象与Json字符串互转(4种转换方式)
Mar 27 Javascript
通过jquery 获取URL参数并进行转码
Aug 18 Javascript
node.js中的fs.readdirSync方法使用说明
Dec 17 Javascript
jquery 判断selection range 是否在容器中的简单实例
Aug 02 Javascript
Angular项目中$scope.$apply()方法的使用详解
Jul 26 Javascript
Angular4学习笔记之准备和环境搭建项目
Aug 01 Javascript
vue-cli3配置与跨域处理方法
Aug 17 Javascript
JavaScript语法约定和程序调试原理解析
Nov 03 Javascript
VueX模块的具体使用(小白教程)
Jun 05 #Javascript
Vuex的热更替如何实现
Jun 05 #Javascript
2分钟实现一个Vue实时直播系统的示例代码
Jun 05 #Javascript
Vue 封装防刷新考试倒计时组件的实现
Jun 05 #Javascript
webpack 如何同时输出压缩和未压缩的文件的实现步骤
Jun 05 #Javascript
vue使用nprogress加载路由进度条的方法
Jun 04 #Javascript
JS+canvas五子棋人机对战实现步骤详解
Jun 04 #Javascript
You might like
phpfans留言版用到的install.php
2007/01/04 PHP
php 上传文件类型判断函数(避免上传漏洞 )
2010/06/08 PHP
解读PHP的Yii框架中请求与响应的处理流程
2016/03/17 PHP
thinkPHP5框架导出Excel文件简单操作示例
2018/08/03 PHP
PHP模型Model类封装数据库操作示例
2019/03/14 PHP
高性能Javascript笔记 数据的存储与访问性能优化
2012/08/02 Javascript
给文字加上着重号的JS代码
2013/11/12 Javascript
checkbox全选所涉及到的知识点介绍
2013/12/31 Javascript
jQuery前端框架easyui使用Dialog时bug处理
2014/12/05 Javascript
老生常谈 关于JavaScript的类的继承
2016/06/24 Javascript
Vue中如何实现轮播图的示例代码
2017/07/27 Javascript
vue element upload实现图片本地预览
2019/08/20 Javascript
vue flex 布局实现div均分自动换行的示例代码
2020/08/05 Javascript
[01:03:09]完美世界DOTA2联赛PWL S2 Forest vs SZ 第二场 11.25
2020/11/26 DOTA
python 实现文件的递归拷贝实现代码
2012/08/02 Python
使用Python的turtle模块画图的方法
2017/11/15 Python
Python OpenCV实现图片上输出中文
2018/01/22 Python
python调用xlsxwriter创建xlsx的方法
2018/05/03 Python
python实现根据文件关键字进行切分为多个文件的示例
2018/12/10 Python
Python3模拟curl发送post请求操作示例
2019/05/03 Python
Python可以实现栈的结构吗
2020/05/27 Python
澳大利亚相机之家:Camera House
2017/11/30 全球购物
联想加拿大官方网站:Lenovo Canada
2018/04/05 全球购物
Parfumdreams英国:香水和化妆品
2019/05/10 全球购物
什么是URL
2015/12/13 面试题
学生发电厂实习自我鉴定
2013/09/22 职场文书
关于元旦的广播稿
2014/02/16 职场文书
租房协议书怎么写
2014/04/10 职场文书
孝敬父母的活动方案
2014/08/31 职场文书
2014年政风行风自查自纠报告
2014/10/21 职场文书
2014年学生会生活部工作总结
2014/11/07 职场文书
优秀教师个人总结
2015/02/11 职场文书
交心谈心活动总结
2015/05/11 职场文书
如何书写先进事迹材料?
2019/07/02 职场文书
python 实现mysql自动增删分区的方法
2021/04/01 Python
nginx日志格式分析和修改
2022/04/28 Servers