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注入技巧
Jun 22 Javascript
IE之动态添加DOM节点触发window.resize事件
Jul 27 Javascript
jquery里的each使用方法详解
Dec 22 Javascript
javascript删除option选项的多种方法总结
Nov 22 Javascript
按钮接受回车事件的三种实现方法
Jun 06 Javascript
详解JavaScript异步编程中jQuery的promise对象的作用
May 03 Javascript
深入浅出ES6新特性之函数默认参数和箭头函数
Aug 01 Javascript
使用 bootstrap modal遇到的问题小结
Nov 09 Javascript
jQuery checkbox选中问题之prop与attr注意点分析
Nov 15 Javascript
详解JavaScript常量定义
Jan 03 Javascript
vue中父子组件传值,解决钩子函数mounted只运行一次的操作
Jul 27 Javascript
vue 组件简介
Jul 31 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
十大“创意”战术!
2020/03/04 星际争霸
PHPMailer邮件类利用smtp.163.com发送邮件方法
2008/09/11 PHP
PHP初学者最感迷茫的问题小结
2010/03/27 PHP
php文件夹的创建与删除方法
2015/01/24 PHP
PHP获取网站中各文章的第一张图片的代码示例
2016/05/20 PHP
ThinkPHP 5.x远程命令执行漏洞复现
2019/09/23 PHP
Laravel 自动生成验证的实例讲解:login / logout
2019/10/14 PHP
页面加载完后自动执行一个方法的js代码
2014/09/06 Javascript
jquery表单验证需要做些什么
2015/11/17 Javascript
Bootstrap警告(Alerts)的实现方法
2017/03/22 Javascript
vue项目国际化vue-i18n的安装使用教程
2018/03/14 Javascript
react 应用多入口配置及实践总结
2018/10/17 Javascript
100行代码实现一个vue分页组功能
2018/11/06 Javascript
JS与SQL方式随机生成高强度密码示例
2018/12/29 Javascript
JS数组扁平化(flat)方法总结详解
2019/06/24 Javascript
用vue写一个日历
2020/11/02 Javascript
VueCli生产环境打包部署跨域失败的解决
2020/11/13 Javascript
js调用网络摄像头的方法
2020/12/05 Javascript
[56:46]2018DOTA2亚洲邀请赛 3.31 小组赛 B组 VP vs Effect
2018/04/01 DOTA
使用Python编写提取日志中的中文的脚本的方法
2015/04/30 Python
Python入门学习指南分享
2018/04/11 Python
利用Python脚本实现自动刷网课
2020/02/03 Python
python实现引用其他路径包里面的模块
2020/03/09 Python
Pyecharts地图显示不完成问题解决方案
2020/05/11 Python
Python3爬虫中识别图形验证码的实例讲解
2020/07/30 Python
python excel多行合并的方法
2020/12/09 Python
HTML5对手机页面长按会粘贴复制禁用的解决方法
2016/07/19 HTML / CSS
HTML5 离线应用之打造零请求、无流量网站的解决方法
2013/04/25 HTML / CSS
美国豪华时尚女性精品店:Kirna Zabête
2018/01/11 全球购物
Joules官网:女士、男士和儿童服装和鞋类
2018/10/23 全球购物
中文专业毕业生自荐信
2013/10/28 职场文书
公司活动总结范文
2014/07/01 职场文书
环境日宣传活动总结
2014/07/09 职场文书
2019自荐信范文集锦!
2019/07/03 职场文书
解决Maven项目中 Invalid bound statement 无效的绑定问题
2021/06/15 Java/Android
Python Flask实现进度条
2022/05/11 Python