Vue 组件传值研究

发布于 2021-12-14 12:43:17 字数 4497 浏览 1136 评论 0

1. 问题

Vue 的项目中有如下的代码,需要根据不同字典的数据去展示下拉组件:

<template>
  <el-select v-model="product.carId" placeholder="请选择车型 >
    <el-option
      v-for="item in options"
      :key="item.id"
      :label="item.name"
      :value="item.id"
    ></el-option>
  </el-select>
</template>

<script>
  export default {
    data() {
      return {
        options: Utils.get('PRODUCT_TYPE')
      }
    }
  }
</script>

问题在于很多 component 中都需要用到这样的代码片段,而且很多都是重复的某个字典,书写麻烦,代码冗余。

2. 分析

Vue 的官方文档 提供了组件封装的一些介绍。下面是摘自官方文档的说明:

自定义事件也可以用于创建支持 v-model 的自定义输入组件。记住:

<input v-model="searchText">

等价于:

<input :value="searchText" @input="searchText = $event.target.value">

当用在组件上时,v-model 则会这样:

<custom-input :value="searchText" @input="searchText = $event"></custom-input>

注意:当用在组件上时,v-model 则会这样 这个句话有一些隐含信息

我们先假定要封装一个简单的 input 的组件,你觉得如下的代码能达到目的吗?

// 调用代码

<tsp-input v-model="name"></tsp-input>

//组件定义代码

<template>
    <input type="text" v-model="value">
</template>

<script>
export default {
  props: ['value']
}
</script>

不妨自己加些输出展示,可以看到,组件定义中的值改变了,并不会改变外部的值,也就是说并不管用。进一步分析:

v-model 等同于 :value @input,是区别对待的。先明确一个概念,directivevue 所有用到 v- 属性的类型的统称,所有带 v- 类型的元素其实都是在跟directive打交道,directive 再跟底层的原生的元素打交道。

(1) 当v-model 被使用在 input 中的时候

input 其实是 directiveInput(自己随意取名),来自原生input的数据,会被隐式地将数据 通过 $emit 传递给 directiveInput,对此 directiveInput 的默认接收到数值的行为是:searchText = $event.target.value

(2)当它被使用在自定义的组件中的时候

我们在 tsp-input 中使用 v-model,那么数据的流转是 原生inputdirectiveInput ,再到 directiveTspInputdirectiveInputdirectiveTspInput都有接收值的默认行为,但是不具备往外继续传递的行为。即 tsp-input虽然挂了 input 的事件,但是无法被触发。这点不同于 vue 介入 原生input 将值传递给了 directiveInput

继续往外面传值,必须显示的声明传值过程,如下:

// 调用代码

<tsp-input v-model="name"></tsp-input>

//组件定义代码

<template>
<input type="text" :value="value" @input="$emit('input', $event.target.value)">
</template>

<script>
export default {
  props: ['value']
}

3. 应用

假定我们需要基于 el-select 封装得到一个 tsp-select,代码大概是这样的,实用有效:

//实际调用
<tsp-select v-model="product.cardId" dictName="PRODUCT_TYPE"></tsp-select>

// tsp-select.vue 封装
<template>
  <el-select :value="product.carId" @input="$emit('input', $event)" 
    placeholder="请选择车型>
    <el-option
      v-for="item in options"
      :key="item.id"
      :label="item.name"
      :value="item.id"
    ></el-option>
  </el-select>
</template>

<script>
  export default {
    data() {
      return {
        options: Utils.get(this.dictName)
      }
    }
  }
</script>

4. 总结和完整代码

使用 ElementUIel-select 能够成功使用 v-model,说明 原生inputdirectiveInput再到directiveElSelect的数据流转是ok的(即在el-select代码内部是有封装 $emit('input', $event) 的),那么到了我们的 tsp-select中,想要也能被直接使用,也需要将值继续往外传递。如下是完整封装代码:

tsp-select.vue

<template>
   <el-select :value="value" @input="$emit('input', $event)" placeholder="请选择">
      <el-option
        v-for="item in options"
        :key="item.code"
        :label="item.text"
        :value="item.code"
      ></el-option>
    </el-select>
</template>

<script>
export default {
  props: {
    value: [Number, String],
    dictName: String,
  },
  data() {
    return {
      options: G.D.get(this.dictName)
    }
  },
}
</script>

和代码调用

<el-form-item label="产品类型" prop="carId">
  <tsp-select v-model="product.cardId" dictName="PRODUCT_TYPE"></tsp-select>
</el-form-item>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

文章
评论
504 人气
更多

推荐作者

三岁铭

文章 0 评论 0

alipaysp_VP2a8Q4rgx

文章 0 评论 0

拧巴小姐

文章 0 评论 0

1649543945

文章 0 评论 0

深居我梦

文章 0 评论 0

tongsw

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文