Vue中v-model解析、sync修饰符解析

上善若水,水善利萬物而不爭。——《道德經》
简介

在平时开发是常常用到一些父子组件通讯,常常用到props、vuex等等,这里面记录另外的三种方式v-model、sync是怎么使用,再说是怎么实现,其实v-model、sync都是语法糖。还有$attr、$listener实现父子组件通讯。
使用方式
v-model

    2.2.0+ 新增

v-mode1其实就是一个语法糖,默认会利用名为value的props和名为input的事件,可是像单选框、复选框等类型的输入龙剑可能会讲value特性用于不一样的目的。

v-model的使用场景:当子组件须要改变父组件经过props传入的值

父组件

    父组件经过v-model绑定值
    如需根据v-model传入的值改变,而触发其余更新请经过watch传入的值

子组件

    声明model对象 设置事件event和prop字段
    经过porps接受父组件传送值
    修改是经过this.$emit广播事件

代码示例:

父组件代码

<template>
  <children v-model="message"></children>
</template>
<script>
import children from "./children.vue";
export default {
  components: {
    children
  },
  data() {
    return {
      message: "parent"
    };
  },
  watch: {
    // 监听message变化
    message(newV, oldV) {
      console.log(newV, oldV);
    }
  }
};
</script>

子组件代码

<template>
  <h1>{{ message }}</h1>
</template>
<script>
export default {
  model: {
    prop: "message", //这个字段,是指父组件设置 v-model 时,将变量值传给子组件的 msg
    event: "input" //这个字段,是指父组件监听 parent-event 事件
  },
  props: {
    message: String //此处必须定义和model的prop相同的props,由于v-model会传值给子组件
  },
  mounted() {
    //这里模拟异步将msg传到父组件v-model,实现双向控制
    setTimeout(_ => {
      this.$emit("input", "children");
      //将这个值经过 emit 触发parent-event,将some传递给父组件的v-model绑定的变量
    }, 1500);
  }
};
</script>

上面这个示例是经过v-model实现的,下面不经过v-model实现一样效果。
不使用 v-model 实现

代码示例以下:

父组件代码修改

<template>
  <Children :message="message" @input="(event) => { message = event }"/>
</template>
<script>
// 不变
</script>

子组件代码修改

<template>
  // 不变
</template>
<script>
export default {
  props: {
    message: String
  },
  mounted() {
    setTimeout(() => {
      this.$emit("input", "children");
    }, 1500);
  }
};
</script>

只是把v-model拆分为props和@input事件,子组件不须要配置model,只须要接受props和经过this.$emit广播事件就能够。 固然这个相对于v-model方法比较简便,可是灵活度查不少,选择使用那种看我的喜爱。 在线地址:

不能放iframe只能放一放一个连接了本篇代码实例
sync

    2.3.0+ 新增

在有些状况下,咱们可能须要对一个 prop 进行**“双向绑定”。不幸的是,真正的双向绑定**会带来维护上的问题,由于子组件能够修改父组件,且在父组件和子组件都没有明显的改动来源。

这也是为何咱们推荐以 update:myPropName 的模式触发事件取而代之。同时也能够经过sync修饰符来实现。

在上面代码的基础上大体修改以下:

父组件

    经过修改触发事件input为update:myPropName实现相同效果

子组件

    经过修改this.$emit(update:myPropName)

代码以下:

父组件代码修改

  // 修改以下
  <Children :message="message" @update:input="(event) => { message = event }"/>

子组件代码修改

  // 其余不变
  this.$emit("update:input", "children");

sync实现

上面的代码能够经过sync简写为下面代码:

父组件代码修改

  // 修改以下
  <Children :messag.sync="message"/>

子组件代码修改

  // 其余不变
  this.$emit("update:messag", "children");

同时sync也支持对象,要配合v-bind实现能够简写为:,可是要注意这个对象以下两条:

    注意带有 .sync 修饰符的 v-bind 不能和表达式一块儿使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的属性名,相似 v-model。 将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是没法正常工做的,由于在解析一个像这样的复杂表达式的时候,有不少边缘状况须要考虑。

attrs、listeners
$attrs

    2.4.0 新增

    类型:{ [key: string]: string }
    只读
    详细: 包含了父做用域中不做为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含全部父做用域的绑定 (class 和 style 除外),而且能够经过 v-bind="$attrs" 传入内部组件——在建立高级别的组件时很是有用。

$listeners

    2.4.0 新增

    类型:{ [key: string]: Function | Array<Function> }
    只读
    详细: 包含了父做用域中的 (不含 .native 修饰器的) v-on 事件监听器。它能够经过 v-on="$listeners" 传入内部组件——在建立更高层次的组件时很是有用。

实现通讯

实现父子组件通讯

父组件代码

<template>
  <div class="parent">
    <Children
      :message="message"
      @upDate="upDate"
      type="del"
      @input="(event) => { message = event }"
    />
  </div>
</template>

<script>
import Children from "./Children";
export default {
  components: {
    Children
  },
  data() {
    return {
      message: "parent",
      type: "del"
    };
  },
  methods: {
    upDate (event) {
      console.log(event);
      this.type = event;
    }
  },
  watch: {
    message: function() {
      console.log("更新message值为" + this.message);
    }
  }
};
</script>

子组件代码

<template>
  <div v-bind="$attrs" v-on="$listeners" class="children">{{message}} <span @click="$listeners.upDate('data')">{{$attrs.type}}</span></div>
</template>

<script>
export default {
  props: {
    message: String
  },
  mounted() {
    // console.log(this.$attrs);
    // console.log(this.$listeners);
    setTimeout(() => {
      this.$emit("input", "children");
      this.$emit('upDate', 'add')
    }, 1500);
  }
};
</script>

同时$attrs、$listeners都是能够跨域父子组件,能够父子子子组件传递,相似于react中的context,只是一部分设计理念相同。
总结

其实就是检测到.sync修饰符,在complier阶段会编译生成多个prop,生成多个事件。其实像这个指令、修饰符、自定义指令都是在vue编译是解析成为v8能执行的代码。

不管是vue、babel、react的complier编译阶段大体分为三个阶段:

    经过词法解析parse生成抽象AST或抽象代码树
    优化AST,好比vue标记静态节点,babal中抽取静态代码,这个阶段被称为optimize或者优化AST树
    在AST代码的阶段上,生成可执行代码,这个过程能够叫作codegen

v-model、sync均可以实现父子组件通讯,而且能够在子组件中修改父组件传入的值。在日常见解的时候进场能够用到这两种方式,具体选择那种方式看我的喜爱。在element-ui这个input组件也用到相关的属性。
相关文章
相关标签/搜索