Vue项目中通过v-model封装ElementUI组件

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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 4,989评论 0 29
  • VUE介绍 Vue的特点构建用户界面,只关注View层简单易学,简洁、轻量、快速渐进式框架 框架VS库库,是一封装...
    多多酱_DuoDuo_阅读 2,625评论 1 17
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,125评论 0 6
  • 一、了解Vue.js 1.1.1 Vue.js是什么? 简单小巧、渐进式、功能强大的技术栈 1.1.2 为什么学习...
    蔡华鹏阅读 3,293评论 0 3
  • 组件(Component)是Vue.js最核心的功能,也是整个架构设计最精彩的地方,当然也是最难掌握的。...
    六个周阅读 5,520评论 0 32