组件封装之入门,还扯到了diff操作
为什么要封装
最近最后台管理项目,表单写的有点多,其中下拉框代码最占地方,整个文件显的很大,我就想把它封起来,正好做表格的时候封装了一个根据金额正负显示的颜色的小组件。这次把两个组件都来出来说说。
根据正负显示颜色
封装组件肯定要绑定数据,子组件离不开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操作更快更准确找到这个子组件。
作者:常彬
链接:https://juejin.cn/post/7024453018779123720