prop 的 sync 修饰符与自定义指令 v-model

prop 的 sync 修饰符

允许我们通过 prop 进行双向数据绑定而不触发子组件修改 props 的警告

使用方式如下

子组件 Nam.vue

props:{
  name:{
		defalut:'x',
		type:String
}
}
methods:{
  changeName(){
    this.$emit(update:name,somevalue)// Tip:update字段是必须的,后面跟你需要改变的prop名称
  }
}

父组件

<Name :name.sync="name"></Name>
<!--严格要求书写格式-->

export defalut { name:'s' watch:{ 's':function(newValue,oldValue){
console.log('新的名字'+newValue) } } }

如果你已经开始使用 TS 语法,并用到了vue-property-decorator这个库,那么你可以像下面这样实现prop. sync

子组件 Name.vue

说明:

@PropSync装饰器与@prop用法类似,二者的区别在于:

  • @PropSync 装饰器接收两个参数 propName: string 表示父组件传递过来的属性名 options: Constructor | Constructor[] | PropOptions@Prop的第一个参数一致
  • @PropSync会生成一个新的计算属性
import { Vue, Component, PropSync } from 'vue-property-decorator'
@Component
export default class MyComponent extends Vue {
  @PropSync('propA', { type: String, default: 'abc' }) syncedPropA!: string
}

父组件

<Name :name.sync="name"></Name>
<!--严格要求书写格式-->
import { Vue, Component, Watch } from 'vue-property-decorator' @Component export
default class MyComponent extends Vue { name="s" @Watch('name') function
nameChange(n,o){ console.log('新的名字'+n) } }

更多 vue-property-decorator 文章可以点击这里Github掘金

自定义指令 v-model

如果想要通过 v-model 指令实现双向数据绑定,我们可以像下面这样进行尝试

<!-- children.vue -->
<template>
    <h1>{{ msg }}</h1>
</template>
<script>

export default{
    model:{
        prop:'msg',//这个字段,是指父组件设置 v-model 时,将变量值传给子组件的 msg
        event:'parent-event'//这个字段,是指父组件监听 parent-event 事件,也可以是自己定义的名字
    },
    props:{
        msg:String //此处必须定义和model的prop相同的props,因为v-model会传值给子组件
    },
    mounted(){
    //这里模拟异步将msg传到父组件v-model,实现双向控制
        setTimeout(**=>{
            let some = '3秒后出现的某个值';//子组件自己的某个值
            this.$emit('parent-event',some);// 触发很重要,否则没办法双向绑定,对应上面的event
            //将这个值通过 emit 触发parent-event,将some传递给父组件的v-model绑定的变量
        },3000);
    }
}
</script>
<!-- parent.vue -->
<template>
    <children v-model="parentMsg"></children>
</template>
<script>
import children from 'path/to/children.vue';
export default{
    components:{
        children
    },
    data(){
        return{
            parentMsg:'test'
        }
    },
    watch:{
        parentMsg(newV,oldV){
            console.log(newV,oldV);
            //三秒后控制台会输出
            //'3秒后出现的某个值','test'
        }
    }
}
</script>

在使用vue-property-decorator 这个库的时候,用到了 model 这个语法糖,使用基本方法如下

 @Model('parent-event', { type: String, default: '' }) value!: string

如果想要实现双向绑定的 v-model 还需要去触发更新需要的值

this.$emit('parent-event', this.syncedvalue)

如果没有主动触发更新,则只能实现使用 v-model 的 props(这句话需要实际体验一下),没有实现双向绑定,下面看一个官方的例子

import { Vue, Component, Model } from 'vue-property-decorator'

@Component
export default class YourComponent extends Vue {
  @Model('change', { type: Boolean }) readonly checked!: boolean
}

它等同于

export default {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: {
      type: Boolean
    }
  }
}
// 仅仅是props的传递

如果你对这种方式还有疑问,可以结合Vue 官方文档进行理解,然后在回过头来看上面的实现。如下

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

现在在这个组件上使用 v-model 的时候:

<base-checkbox v-model="lovingVue"></base-checkbox>

这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的属性将会被更新。

注意你仍然需要在组件的 props 选项里声明 checked 这个 prop。