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 实现模态对话框 源代码大全
May 02 Javascript
JavaScript 判断指定字符串是否为有效数字
May 11 Javascript
JS实现鼠标单击与双击事件共存
Mar 08 Javascript
触屏中的JavaScript事件分析
Feb 06 Javascript
在Mac OS下使用Node.js的简单教程
Jun 24 Javascript
不能不知道的10个angularjs英文学习网站
Mar 23 Javascript
node.js实现端口转发
Apr 14 Javascript
JS异步文件分片断点上传的实现思路
Dec 25 Javascript
Node.js实现连接mysql数据库功能示例
Sep 15 Javascript
使用Vuex实现一个笔记应用的方法
Mar 13 Javascript
vue如何在项目中调用腾讯云的滑动验证码
Jul 15 Javascript
vue中解决微信html5原生ios虚拟键返回不刷新问题
Oct 20 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
使用Apache的rewrite技术
2006/06/22 PHP
php执行sql语句的写法
2009/03/10 PHP
php 流程控制switch的简单实例
2016/06/07 PHP
如何在PHP中使用AES加密算法加密数据
2020/06/24 PHP
简单JS代码压缩器
2006/10/12 Javascript
屏蔽Flash右键信息的js代码
2010/01/17 Javascript
javascript 自动填写表单的实现方法
2010/04/09 Javascript
JQuery中如何传递参数如click(),change()等具体实现
2013/04/28 Javascript
node.js中的fs.appendFile方法使用说明
2014/12/17 Javascript
JS实现的新浪微博大厅文字内容滚动效果代码
2015/11/05 Javascript
跨域请求的完美解决方法(JSONP, CORS)
2016/06/12 Javascript
Bootstrap实现圆角、圆形头像和响应式图片
2016/12/14 Javascript
提高Web性能的前端优化技巧总结
2017/02/27 Javascript
JS实现div模块的截图并下载功能
2017/10/17 Javascript
webpack下实现动态引入文件方法
2018/02/22 Javascript
JavaScript求一个数组中重复出现次数最多的元素及其下标位置示例
2018/07/23 Javascript
如何使用pm2快速将项目部署到远程服务器
2019/03/12 Javascript
浅谈layui里的上传控件问题
2019/09/26 Javascript
js实现有趣的倒计时效果
2021/01/19 Javascript
[02:15]2015国际邀请赛选手档案IG.Ferrari 430
2015/07/30 DOTA
python实现排序算法
2014/02/14 Python
python实现域名系统(DNS)正向查询的方法
2016/04/19 Python
Python + selenium自动化环境搭建的完整步骤
2018/05/19 Python
Python 利用pydub库操作音频文件的方法
2019/01/09 Python
从列表或字典创建Pandas的DataFrame对象的方法
2019/07/06 Python
CSS实现雨滴动画效果的实例代码
2019/10/08 HTML / CSS
详解css3 flex弹性盒自动铺满写法
2020/09/17 HTML / CSS
培训专员岗位职责
2014/02/26 职场文书
领导接待方案
2014/03/13 职场文书
关于中国梦的演讲稿
2014/04/23 职场文书
关于雷锋的演讲稿
2014/05/10 职场文书
立志成才演讲稿
2014/09/04 职场文书
群众路线表态发言材料
2014/10/17 职场文书
成都人事代理协议书
2014/10/25 职场文书
关于感恩的歌曲整理(8首)
2019/08/14 职场文书
Redis的字符串是如何实现的
2021/10/24 Redis