美文网首页
无星的前端之旅(一)——vue 自定义组件使用v-model/.

无星的前端之旅(一)——vue 自定义组件使用v-model/.

作者: 无星灬 | 来源:发表于2019-12-20 16:51 被阅读0次

背景:

正常情况下,vue是由父到子的单向数据流。但总会碰到一些操蛋的需求,想直接在子组件去修改对应数据。这时候就会发现,报警告️了。只能写子组件通知父组件修改对应数据,代码就又大又不优雅。

这时候就会想,v-model怎么实现的,自己封装的组件能不能用?还有没有别的方式。

于是乎有了这篇憨批文章。

其实相关文章也有很多了,但总觉得还是要自己总结一下比较好。

先上官网链接

自定义组件使用model

使用 JavaScript 代替模板功能

这里我想举好几个例子,但是又不知道怎么分点,因此我就随意分了

一.默认value和input的例子

子组件如下,test1.vue

<!--v-model:https://cn.vuejs.org/v2/api/#model-->
<template>
  <div class="main">
    <div @click="sub">
      -
    </div>
    <input
      v-model="value"
      type="text"
      style="width:160px"
      @input="$emit('input', $event.target.value)"
    />
    <!-- @input="$emit('input', $event.target.value)" -->
    <div @click="add">
      +
    </div>
  </div>
</template>

<script>
export default {
  components: {},
  props: {
    value: {
      type: [Number, String],
      default: 0,
    },
  },
  data: () => ({}),
  computed: {},
  watch: {},
  // created() {},
  mounted() {},
  methods: {
    add() {
      // this.value = this.value + 1
      this.$emit('input', Number(this.value) + 1)
    },
    sub() {
      this.$emit('input', Number(this.value) - 1)
    },
  },
}
</script>
<style lang="less" scoped>
.main {
  display: flex;
  flex-direction: row;
}
</style>

父组件如下

<!---->
<!---->
<template>
  <div class="main">
    <Test1 v-model="nums1" />
    <Test2 v-model="nums2" />
    <p>num1:{{ nums1 }}</p>
    <p>num2:{{ nums2 }}</p>
  </div>
</template>

<script>
import Test1 from './test1.vue'
import Test2 from './test2.vue'
export default {
  // import引入的组件需要注入到对象中才能使用
  components: {
    Test1,
    Test2,
  },
  data: () => ({
    nums1: 0,
    nums2: 0,
  }),
  computed: {},
  watch: {},
  mounted() {},
  // 方法集合
  methods: {},
}
</script>
<style lang="less" scoped>
.main {
}
</style>


官网说明

从官网链接可以看到自定义组件,默认会把value这个key作为prop,默认有个input事件。(跟我用不用input这个dom没关系,可以换成<p>{{value}}</p>) 体现在代码中就是。

注释

效果如下图

演示

可以看到,跟随变化,且右边没有报警告

二.非默认值,自己写

因为value本身可能是某些组件的'关键字',我们更需要的是能自定义的值

子组件test2.vue

<!--v-model:https://cn.vuejs.org/v2/api/#model-->
<template>
  <div class="main">
    <div @click="sub">
      -
    </div>
    <p>{{ curvalue }}</p>
    <div @click="add">
      +
    </div>
  </div>
</template>

<script>
export default {
  model: {
    prop: 'curvalue',
    event: 'updatecurvalue',
  },
  props: {
    curvalue: {
      type: [Number, String],
      default: 0,
    },
  },
  methods: {
    add() {
      this.$emit('updatecurvalue', Number(this.curvalue) + 1)
    },
    sub() {
      this.$emit('updatecurvalue', Number(this.curvalue) - 1)
    },
  },
}
</script>
<style lang="less" scoped>
.main {
  display: flex;
  flex-direction: row;
}
</style>

如图

如上图,通过model下的prop接收对应的事件,去做当前值的绑定和当前值变更的事件绑定。

效果图

3.其实还有一种方式.sync

sync官方文档

test3.vue

<!--v-sync:https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-%E4%BF%AE%E9%A5%B0%E7%AC%A6-->
<template>
  <div class="main">
    <div @click="sub">
      -
    </div>
    <p>{{ curvalue }}</p>
    <div @click="add">
      +
    </div>
  </div>
</template>

<script>
export default {
  props: {
    curvalue: {
      type: [Number, String],
      default: 0,
    },
  },
  methods: {
    add() {
      this.$emit('update:curvalue', Number(this.curvalue) + 1)
    },
    sub() {
      this.$emit('update:curvalue', Number(this.curvalue) - 1)
    },
  },
}
</script>
<style lang="less" scoped>
.main {
  display: flex;
  flex-direction: row;
}
</style>

父组件

<!---->
<template>
  <div class="main">
    <Test3 :curvalue.sync="nums1" />
    <p>num1:{{ nums1 }}</p>
  </div>
</template>

<script>
import Test3 from './test3.vue'
export default {
  // import引入的组件需要注入到对象中才能使用
  components: { Test3 },
  data: () => ({
    nums1: 0,
    nums2: 0,
  }),
  computed: {},
  watch: {},
  mounted() {},
  // 方法集合
  methods: {},
}
</script>
<style lang="less" scoped>
.main {
}
</style>

test3.vue

效果如下

如图

使用你封装的控件的人,一看到这个.sync就知道,肯定是绑定了。

相关文章

网友评论

      本文标题:无星的前端之旅(一)——vue 自定义组件使用v-model/.

      本文链接:https://www.haomeiwen.com/subject/ssyinctx.html