likes
comments
collection
share

都2023年了,我绝对不允许,你还不会v-model原理

作者站长头像
站长
· 阅读数 37

都2023年了,我绝对不允许,你还不会v-model原理

前言:v-model是什么? 相信对使用vue框架的伙伴们来说,v-model的使用都能信手沾来,熟悉的不能再熟悉,也都知道v-model其实是个语法糖。不过其究竟是怎么实现的双向数据绑定,很大一部分伙伴们还是心存疑虑。本文就根据最简单的案例和基于实际项目中最常用的实例来从两个角度讲解v-model

我们前端开发中最重要的一个环节就是要与用户做交付,拿到用户数据。

以Element-ui为栗子,常用的交付组件有 el-input / el-select / el-radio 等等...

那我们要使用v-model拿到用户传入的数据,一般都会这么操作,如下

<template>
  <div>
      <el-input v-model="inputValue" placeholder="请输入内容"></el-input>
      <el-select v-model="ballValue" placeholder="请选择">
        <el-option label="篮球" :value="0"></el-option>
        <el-option label="足球" :value="1"></el-option>
        <el-option label="排球" :value="2"></el-option>
      </el-select>
  </div>
</template>

<script>
export default {
  data() {
    return {
      inputValue: '',
      ballValue:0
    };
  },
};
</script>

此时Vue,data里面定义的字段通过v-model与视图组件就做好了关联。

然而今天咱要讲的并不是它具体咋用. 而是探讨v-model在官网里面为什么会被称为语法糖? 它又是谁的语法糖? 闲言少叙,直接看下面代码

<template>
  <div>
      <!--这种写法与v-model达到的效果是一样的哦-->
      <el-input :value='inputValue' @input='inputValue = $event.target.value' />
  </div>
</template>

<script>
export default {
  data() {
    return {
      inputValue: '',
    };
  },
};
</script>

接下来想必伙伴们心里就有底了,这么一大长串代码最后实现出来的效果就是v-model呀,那么小伙伴心里就清楚了:value='inputValue' @input='inputValue = $event.target.value' 的语法糖,就是v-model,怎么样,伙伴们是不是挺简单的呀!

别急伙伴们,文章到了这里还没完呢,接下来咱就讲一讲自定义组件,怎么绑定v-model。接着往下看!

首先怎么去定义一个组件咱不过多赘述,如果小伙伴们对vue定义组件还有疑惑,可以先移步vue的官网学习!咱直接看代码!

//父组件
<template>
    <Select :value='selectValue' @input="selectValue = $event"' />
</template>

<script>
export default {
  data() {
    return {
      selectValue: '',
    };
  },
};
</script>
//子组件
<template>
      <el-select v-model="value" placeholder="请选择" @change='BallChange'>
        <el-option label="篮球" :value="0"></el-option>
        <el-option label="足球" :value="1"></el-option>
        <el-option label="排球" :value="2"></el-option>
      </el-select>
</template>

<script>
export default {
  props:['value'], //接收父组件传过来的值
  methods: {
    BallChange() {
      this.$emit('input',this.value) //定义input方法,把值传回
    },
  },
};
</script>

这时伙伴们可能会有疑惑? 你刚说演示组件的v-model,那上面的代码跟v-model有啥关系呀?

伙伴们要记得,咱刚才不是说v-model是语法糖么? 我之所以先这么写,是用的你们最熟悉的父子组件传值方式,便于理解!那么咱马上写成语法糖, 稍微改造一下, 如下:

//父组件
<template>
    <Select v-model='selectValue'/>
</template>

<script>
export default {
  data() {
    return {
      selectValue: '',
    };
  },
};
</script>

这样整个组件的绑定v-model就完成了,是不是也挺简单呀**。**

注意:有的小伙伴们可能会问? this.$emit('input',this.value) 这个事件能改名字吗? 硬要写 input

伙伴们这个是硬性要求呀。 又回到上面的话题, v-model是谁的语法糖呀? 是 value 与 @input的组合体,所以名字不能乱改。那有的小伙伴就不服了!就要改,就不想用这2个名字。别急呀,后面咱都会把解决方法告诉大家,接着往下看呗

这里大家要记住一点的就是v-model就是value 与 @input的组合体,既然大家知道了这个概念后,咋写自定义组件v-model就可以任意发挥了呗,下面是几种常用的写法:

第一种 methods 方式

//父组件
<template>
    <Select v-model='selectValue' />
</template>

<script>
export default {
  data() {
    return {
      selectValue: '',
    };
  },
};
</script>
//子组件
<template>
      <el-select v-model="value" placeholder="请选择" @change='BallChange'>
        <el-option label="篮球" :value="0"></el-option>
        <el-option label="足球" :value="1"></el-option>
        <el-option label="排球" :value="2"></el-option>
      </el-select>
</template>

<script>
export default {
  props:['value'],
  methods: { 
    BallChange() {
      this.$emit('input',this.value) 
    },
  },
};
</script>

第二种 watch 方式

//父组件
<template>
    <Select v-model='selectValue' />
</template>

<script>
export default {
  data() {
    return {
      selectValue: '',
    };
  },
};
</script>
//子组件
<template>
      <el-select v-model="value" placeholder="请选择">
        <el-option label="篮球" :value="0"></el-option>
        <el-option label="足球" :value="1"></el-option>
        <el-option label="排球" :value="2"></el-option>
      </el-select>
</template>

<script>
export default {
    props:['value'],
    watch:{
        value(val){
          this.$emit('input',val)
        }
    },
};
</script>

第三种 model 方式

//父组件
<template>
    <Select v-model='selectValue' />
</template>

<script>
export default {
  data() {
    return {
      selectValue: '',
    };
  },
};
</script>
//子组件
<template>
  <el-select v-model="val"
             placeholder="请选择"
             @change="BallChange">
    <el-option label="篮球"
               :value="0"></el-option>
    <el-option label="足球"
               :value="1"></el-option>
    <el-option label="排球"
               :value="2"></el-option>
  </el-select>
</template>

<script>
export default {
  model: {
    prop: 'val', //自定义,但是要与props对应上
    event: 'aa',//自定义,但是要与this.$emit里面对应上
  },
  props: {
    val: [String, Number],
  },

  methods: {
    BallChange() {
      this.$emit('aa', this.val)
    },
  },
}
</script>

注意 上面的例子在游览器会报一个vue的错 Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "drawer" 这个是因为子组件内部修改props中父组件传过来的值

小伙伴们,只需做如下修改,拿第一个例子为例:

//父组件
<template>
    <Select v-model='selectValue' />
</template>

<script>
export default {
  data() {
    return {
      selectValue: '',
    };
  },
};
</script>
//子组件
<template>
      <el-select v-model="newValue" placeholder="请选择" @change='BallChange'>
        <el-option label="篮球" :value="0"></el-option>
        <el-option label="足球" :value="1"></el-option>
        <el-option label="排球" :value="2"></el-option>
      </el-select>
</template>

<script>
export default {
  props:['value'],
  data(){
      return {
          newValue:this.value //创建一个新值,接收一下父组件传过来的值
      }
  },
  methods: {
    BallChange() {
      this.$emit('input',this.newValue) 
    },
  },
};
</script>

好了文章到了这里就接近尾声,伙伴们你们可以去试一试了,还有没学会的小伙伴可以评论区留言。。咱再一起探讨!

转载自:https://juejin.cn/post/7234418257758879799
评论
请登录