zoukankan      html  css  js  c++  java
  • Vue的双向绑定以及组件的自定义事件

    什么是双向绑定

    所谓的双向绑定是指数据发生变化时,视图会同步发生变化,而当视图发生变化时,数据也会同步变化。

    Vue中怎么实现双向绑定

    在Vue中,我们通过v-model来创建双向绑定。

    我们继续用todolist和todoitme组件来示例双向绑定

    1. 在App.vue的data中增加一个message。
      data(){
        return{
          message:"hello world",
          list: [
                  {
                    title: "新课程1",
                    del: false
                  },
                  {
                    title: "新课程2",
                    del: true
                  },
                  {
                    title: "新课程3",
                    del: false
                  }
                ]
        };
      },
    
    1. 在App.vue的template中通过模板语法增加对应的message展示。
        {{message}}
    
    1. 创建一个表单控件,通过v-model实现message的双向绑定。
    <input type="text" v-model="message"/>
    

    全部代码如下

    <template>
      <div id="app">
        <input type="text" v-model="message"/>
        {{message}}
        <todolist>
          <todoitem v-on:delete="handleDelete" v-for="item in list" :key="item.title" data-wen="wen" :title="item.title" :del="item.del">
            <template v-slot:pretext="{val}">
              <label>前置文字{{val}}</label>
            </template>
          </todoitem>
        </todolist>
      </div>
    </template>
    
    <script>
    import todolist from './components/todo-list.vue'
    import todoitem from './components/todo-item.vue'
    
    export default {
      name: 'App',
      components: {
        todolist,
        todoitem
      },
      data(){
        return{
          message:"hello world",
          list: [
                  {
                    title: "新课程1",
                    del: false
                  },
                  {
                    title: "新课程2",
                    del: true
                  },
                  {
                    title: "新课程3",
                    del: false
                  }
                ]
        };
      },
      methods: {
        handleDelete(vtitle){
          console.log("删除工程!",vtitle)
        }
      }
    }
    </script>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    

    效果如下:在表单中修改message,不论是脚本中的message变量还是动态绑定的message模板显示都会同步变化。
    image

    Vue双向绑定的本质

    按照Vue官网介绍,Vue的双向绑定是一种语法糖。本质上是

    负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

    它其实还是一种单向的数据流操作。

    它的还原写法即本质是value属性和input事件的组合,代码如下:(单单相对于input的text控件来说):

    <input type="text" :value="message" @input="handleChange"/>
    
    handleChange(e){
          this.message = e.target.value;
        },
    

    完整代码如下:

    <template>
      <div id="app">
        <input type="text" v-model="message"/>
        <input type="text" :value="message" @input="handleChange"/>
        {{message}}
        <todolist>
          <todoitem v-on:delete="handleDelete" v-for="item in list" :key="item.title" data-wen="wen" :title="item.title" :del="item.del">
            <template v-slot:pretext="{val}">
              <label>前置文字{{val}}</label>
            </template>
          </todoitem>
        </todolist>
      </div>
    </template>
    
    <script>
    import todolist from './components/todo-list.vue'
    import todoitem from './components/todo-item.vue'
    
    export default {
      name: 'App',
      components: {
        todolist,
        todoitem
      },
      data(){
        return{
          message:"hello world",
          list: [
                  {
                    title: "新课程1",
                    del: false
                  },
                  {
                    title: "新课程2",
                    del: true
                  },
                  {
                    title: "新课程3",
                    del: false
                  }
                ]
        };
      },
      methods: {
        handleChange(e){
          this.message = e.target.value;
        },
        handleDelete(vtitle){
          console.log("删除工程!",vtitle)
        }
      }
    }
    </script>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    

    为什么说上述的原始写法只针对于input 的text呢?
    vue官网解释如下:

    v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

    • text 和 textarea 元素使用 value 属性和 input 事件;
    • checkbox 和 radio 使用 checked 属性和 change 事件;
    • select 字段将 value 作为 prop 并将 change 作为事件。
    • .....

    如何为组件添加自定义事件绑定

    原生的双向绑定可以大大简化我们的编码,那么如何为我们自己封装的组件添加自定义的双向绑定呢?

    为了实现这一点,我们需要为我们的组件增加一个model对象,并在model对象中告知vue框架本次双向绑定对应的属性和事件。

    如下示例则是告知vue底层该组件监听checked属性的change事件。

    model: {
        prop: 'checked',
        event: 'change'
      },
    

    我们尝试修改todoitem的template和data,增加选择控件和选择后的文本。

    1. 第一步为组件增加model对象
        model: {
            prop: 'itemCheck',
            event: 'change'
        },
    
    1. 第二步在组件的props中注册itemCheck属性
        props: {
              title: String,
              itemCheck:{
                type: Boolean,
                default: false
              },
              del: {
                type: Boolean,
                default: false
              }
            },
    
    1. 第三步修改template,增加checkbox和选中的状态描述。需要注意的是:需要使用完全实现v-model的本质上的属性绑定和事件编码。
    <template>
        <li>
            <input type="checkbox" :name="vrandom" :key="vrandom" :checked="itemCheck" @change="$emit('change', $event.target.checked)" />
            <slot name="pretext" :val="vrandom"></slot>
            <span class="redsapn" v-if="!del">{{title}}</span>
            <span v-else style="text-decoration:line-through">{{title}}</span>
            <button v-show="!del" @click="handleClick">删除</button>
            <slot name="suftext">默认尾部</slot>
        </li>
    </template>
    
    1. 最后我们在APP.vue中的template中使用todoitem时就可以通过v-model来实现todoitem组件的双向绑定了。
    <template>
      <div id="app">
        <input type="text" v-model="message"/>
        <input type="text" :value="message" @input="handleChange"/>
        {{message}}
        <todolist>
          <todoitem v-on:delete="handleDelete" v-model="Checkedmsg" v-for="item in list" :key="item.title" data-wen="wen" :title="item.title" :del="item.del">
            <template v-slot:pretext="{val}">
              <label>前置文字{{val}}</label>
            </template>
          </todoitem>
        </todolist>
      </div>
    </template>
    

    完整代码如下:

    //App.vue
    <template>
      <div id="app">
        <input type="text" v-model="message"/>
        <input type="text" :value="message" @input="handleChange"/>
        {{message}}
        <todolist>
          <todoitem v-on:delete="handleDelete" v-model="Checkedmsg" v-for="item in list" :key="item.title" data-wen="wen" :title="item.title" :del="item.del">
            <template v-slot:pretext="{val}">
              <label>前置文字{{val}}</label>
            </template>
          </todoitem>
        </todolist>
      </div>
    </template>
    
    <script>
    import todolist from './components/todo-list.vue'
    import todoitem from './components/todo-item.vue'
    
    export default {
      name: 'App',
      components: {
        todolist,
        todoitem
      },
      data(){
        return{
          message:"hello world",
          Checkedmsg:false,
          list: [
                  {
                    title: "新课程1",
                    del: false
                  },
                  {
                    title: "新课程2",
                    del: true
                  },
                  {
                    title: "新课程3",
                    del: false
                  }
                ]
        };
      },
      methods: {
        handleChange(e){
          this.message = e.target.value;
        },
        handleDelete(vtitle){
          console.log("删除工程!",vtitle)
        }
      }
    }
    </script>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    
    //todo-item.vue
    <template>
        <li>
            <input type="checkbox" :name="vrandom" :key="vrandom" :checked="itemCheck" @change="$emit('change', $event.target.checked)" />
            <slot name="pretext" :val="vrandom"></slot>
            <span class="redsapn" v-if="!del">{{title}}</span>
            <span v-else style="text-decoration:line-through">{{title}}</span>
            <button v-show="!del" @click="handleClick">删除</button>
            <slot name="suftext">默认尾部</slot>
        </li>
    </template>
    <script>
    export default {
        model: {
            prop: 'itemCheck',
            event: 'change'
        },
        props: {
              title: String,
              itemCheck:Boolean,
              del: {
                type: Boolean,
                default: false
              }
            },
        data: function() {
              return {
                  vrandom:Math.random()
              };
            },
        methods: {
                handleClick(){
                    console.log("点击删除按钮!");
                    this.$emit('delete',this.title);
                }
            }
    }
    </script>
    <style scoped>
    .redsapn{color: red}
    </style>
    
  • 相关阅读:
    51Nod1136--欧拉函数
    ubuntu裸机镜像问题
    汉诺塔问题
    lwm2m协议
    WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式
    图解大顶堆的构建、排序过程
    WindowsService开发简单入门
    数据结构和算法参考网址
    c#创建windows服务入门教程实例
    C#比较两个对象是否为同一个对象。 Visual Studio调试器指南---多线程应用程序调试(一)
  • 原文地址:https://www.cnblogs.com/wenpeng/p/12288313.html
Copyright © 2011-2022 走看看