为什么要封装
最近最后台管理项目,表单写的有点多,其中下拉框代码最占地方,整个文件显的很大,我就想把它封起来,正好做表格的时候封装了一个根据金额正负显示的颜色的小组件。这次把两个组件都来出来说说。
根据正负显示颜色
封装组件肯定要绑定数据,子组件离不开props。使用value是因为要在父组件的D2组件的columns里调用,默认参数是value。 子组件里的props
props: {
value: {
required: true,
},
},
在子组件中props已经接受数据,并可以用this拿到了,所以我直接在template中使用。在标签中进行style的判断就可以实现颜色改变。这段代码意思是:在value里查找-,如果存在就返回位置,这个返回值一定大余等于-1,这时三元运算符判断通过返回red,显示红色。相反找不到-1返回-1,显示绿色。
<span :style="{ color: String(value).indexOf('-') > -1 ? 'red' : 'green' }">
{{ value }}
</span>
父组件的D2组件里的columns
columns: [
{ title: "金额", key: "money", component: { name: TradeAmount } },
],
这个组件只是用来显示,不需要其他操作,所以最简单。
下拉框的封装
这个要多操作几步 由于子组件要接受一个数组props如下:
props: {
selections: {
type: Array,
},
},
参数接受了要放入下拉框,问题来了。el-option标签作为选择项要遍历数组显示出来;要选择某一项,还要对选中的值进行操作,就需要在el-select里绑定一个值,这里我用的value,其他值也行,只是一个代号,在data里返回。
<el-select v-model="value" placeholder="请选择状态" clearable>
<el-option
v-for="item in selections"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
接下来要考虑选中时,value会发生变化,这样我们可以根据值的变化触发事件,把值传给父组件。这里我用了watch监听,其实在组件使用change绑定方法也可以。这样的话,每次值的变化会被watch监听到,触发onChange方法,从而派发一个input的事件,同时携带value。
methods: {
onChange() {
console.log(this.value);
this.$emit("input", this.value);
},
},
watch: {
value: "onChange",
},
到这里子组件的工作完成了。 下面进行父组件的操作。
- 第一步在父组件中
import引入 - components注册为
perSelect - template进行使用 父组件代码使用如下
<perSelect
v-model="formInline.productSource"
:selections="distributionProductSource"
:key="componentKey"
></perSelect>
下面分开解析:
- 第一部分:
v-model="formInline.productSource"
这个v-model可以分为:value和@input,可以理解为
<input :value="formInline.productSource" @input="formInline.productSource= $event.target.value">
这样一来,就可以在父组件拿到子组件触发的input事件携带的数据,同时复制给formInline.productSource。
- 第二部分
:selections="distributionProductSource"
这个部分就是给子组件传值了。 重点在第三部分
- 第三部分
:key="componentKey"
我们知道循环组件的时候要加key,为什么我这里加key呢?这里简单说一下key的作用,key是虚拟DOM的唯一标识,通过key可以让diff操作准确找到新旧树的不同。然后patch到真实DOM。
我在这里用key,是要利用key变化,会从新渲染组件,不会节点复用。
为什么要避免节点复用呢?
因为我在清空表单,也就是清空formInline.productSource时发现这里变化了,但是子组件里的value没有改遍,仔细想来,我确实只给子组件传了数组,但没从父组件给子组件其他操作。相当于我每次清空表单,虽然子组件的v-model没了,但子组件内部还在,节点就根本没有变化。
现在我要避免这种情况,最简单的就是在父组件引用的子组件上加一个key。每一次清空,改变key的值,这样vue根据这个唯一标识,就会从新开始渲染子组件。
当然也可以用v-if,根据条件判断进行DOM的建立与销毁。但是没有加key好,因为key可以帮助diff操作更快更准确找到这个子组件。