Vue v-model组件封装(类似弹窗组件)

6,318 阅读2分钟

v-model

v-model是vue的一个语法糖,限制在input和textarea等这些表单元素中,官网所给的例子也是仅限于表单组件

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)"
    >
  `
})
<base-checkbox v-model="lovingVue"></base-checkbox>

现在我们如果想把v-model用到除表单之外的自定义组件中,该怎么使用呢,其实官网所给的例子也比较清晰了,只是如果死脑筋的话,那就限制住了,没错说的就是我-.-.

<!--封装的类弹窗组件-->
<template>
    <div>
        <div v-show="value">这是v-model的弹窗组件</div>
    </div>
</template>
<script>
export default {
    props:{
        value:{
            type:Boolean,
            default:false
        }
    }
}
</script>
<!--父组件-->
<template>
    <div>
        <v-model v-model="value"></v-model>
        <button @click="value=true">点击显示</button>
        <button @click="value=false">点击消失</button>
    </div>
</template>
<script>
import VModel from "./Vmodel"
export default {
    components:{VModel},
    data:function(){
        return {
            value:true
        }
    }
}
</script>

其实这样父组件这边已经可以通过v-model对显示和消失进行控制了,但是封装组件的value这个属性名是不能修改的,必须叫value,叫value1就不可以了

props:{
        value1:{  //失效
            type:Boolean,
            default:false
        }
    }

原因,看源码

function transformModel (options, data: any) {
  const prop = (options.model && options.model.prop) || 'value' //子组件不存在options.model,默认给value
  const event = (options.model && options.model.event) || 'input'//event="input"
  ;(data.attrs || (data.attrs = {}))[prop] = data.model.value
  const on = data.on || (data.on = {})
  const existing = on[event]  //undefined
  const callback = data.model.callback  //f()
  if (isDef(existing)) {  //false
    if (
      Array.isArray(existing)
        ? existing.indexOf(callback) === -1
        : existing !== callback
    ) {
      on[event] = [callback].concat(existing)
    }
  } else {
    on[event] = callback  //把回调赋值给监听的函数
  }
}

so,我们就可以加上model属性,进行代码修改

<template>
    <div>
        <div v-show="value">这是v-model的弹窗组件</div>
        <div @click="cancelClick">组件内部调用</div>
    </div>
</template>
<script>
export default {
    props:{
        value:{
            type:Boolean,
            default:false
        }
    },
    model:{
        prop:"value",
        event:'change'
    },
    methods:{
        cancelClick:function(){
            //内部调用这个方法可以进行控制
            this.$emit("change",false)
        }
    }
}
</script>

当然我们也可以通过model属性,对value这个属性名进行修改,也是实现同样的效果

bool:{
        type:Boolean,
        default:false
    },
model:{
    prop:"bool",
    event:'change'
}

注意如果灭有加model属性的话,对props的value属性名修改的话,是没效果的,默认的v-model的event默认修改的还是value

 const prop = (options.model && options.model.prop) || 'value' //子组件不存在options.model,默认给value
  const event = (options.model && options.model.event) || 'input'//event="input"