巧妙利用Vue.extend继承组件实现el-table双击可编辑(不要使用v-if和v-else)
#app{width:100%;高度:100vh;框大小:边框框;padding:50px;}问题描述有一个简单的表格,产品需要双击可编辑看下网上的帖子,大都是dom有两部分,一个是输入框,用来填写编辑状态;另一种是普通标签,用于在非编辑显示状态下呈现单元格文本内容。用v-if和v-else添加一个flag标志,控制编辑状态或显示状态。大致代码如下:{{scope.row.name}}这种方式有适用场景,但是每个el-table-column都必须加上el-input和span以及v-if和v-else。我们来试试动态添加el-input,也就是点击那个单元格,给那个单元格添加el-input使其可以编辑,然后适时去掉。这样,当列数很多的时候,就不用加很多v-if和v-else了。我们先来看看效果图。第一步:给el-table绑定双击事件@cell-dblclick='dblclick',然后在双击事件的回调函数中,可以知道点击了哪一行哪一列,celldom,和点击事件。dblclick(row,column,cell,event){...},这个是饿了么官方提供的,没什么好说的。Step2:关键点Step2.1:cell双击事件后,我们先创建一个el-input标签,然后将被点击的cell的值作为参数props让el-input接收,这样el-input将显示单元格的值,您可以对其进行编辑。问题一:如何创建el-input标签?,客官稍等,下面步骤2.2的答案:将创建的el-input标签替换为原来的cellspan标签,这样就可以看到cell变成了可以输入的输入框了。问题2:如何用新建的el-input标签替换原来的span标签,请稍等,下面会回答步骤2.3的问题。当用户编辑完点击别处,也就是输入框失去焦点时,把el-input输入框的标签去掉,恢复默认的span标签(当然失去焦点的时候,请求到修改数据将被发送)。问题三:如何去掉el-input标签,恢复原来的span标签。等一下,下面的答案将回答这个问题。每次双击创建输入标签进行修改,每次修改后失去焦点,都会恢复默认的单元格显示状态。函数实现了代码思路中的三个问题。一:如何创建el-input标签?我们知道,如果创建一个原生的input标签并指定一个值,是比较简单直接的:avaluetotheinputtagdocument.body.appendChild(input)//给文档body添加input标签,但是el-input标签不能通过上面的方法创建,因为document.createElement()方法可以创建el-input标签,但是dom不认识这个el-input标签,所以页面没有变化。毕竟饿了么的el-input也对input标签进行了两次封装,所以这里我们可以使用Vue.extend()方法继承一个组件并暴露出来,而被继承的组件中还有一个input标签。所以需要使用它,并且可以引入一个新的el输入。关于Vue.extend()的定义,这里不再赘述。有关详细信息,请参阅官方文档。作者之前也写过一篇Vue.extend的文章,传送门:https://segmentfault.com/a/11...首先创建一个.vue文件用于继承//input.vue文件
道具:{cellValue:{类型:字符串|Number,default:"",},}然后定义一个data.js文件,继承input.vue文件,暴露//data.jsimportVuefrom"vue";importdefinedInputfrom"./input.vue";//Vue继承了这个输入组件,相当于一个构造函数constinputC=Vue.extend(definedInput);//把它暴露出来,在需要导入的地方exportdefault{inputC,}在页面中导入使用//page。vueimportextendComponentsfrom"./threeC/data";//1.引入newextendComponents.inputC({//2.实例化propsData:{//使用propsData对象传递参数,子组件可以接收cellValueinprops:cellValue,//传递cell的值},}).$mount(cell.children[0]);//3.挂载propsData对象给继承的组件传递参数,或者传递一个函数,继承组件通过这个函数通知外部组件,完整代码见下面细节代码问题二、三:el-input标签和span标签的来回替换使用$mount方法来回替换恢复。$mount可以在父dom元素上追加一个子dom元素,相当于appendChild,这里需要有一个replacement时机是当实例化组件中的el-input失去焦点时通知外部组件,所以可以外部使用,将propsData中的一个函数传递给继承的组件,例如://外部组件传递newextendComponents.inputC({propsData:{cellValue:cellValue,//传递单元格的值saveRowData:this.saveRowData,//传递通知的回调函数,可以在继承的组件中触发},}).$mount(cell.children[0]);saveRowData(params){console.log('收到一个继承组件的消息通知,参数为:',params)}//内部组件失去焦点时通知
道具:{cellValue:{类型:字符串|Number,default:"",},saveRowData:Function,//外部,传入一个函数,当el-input失去焦点时,通过这个函数通知外部}blurFn(){//失去焦点,再次抛出,通知外部this.saveRowData({cellValue:this.cellValue,//其他参数});},这样当内层失去焦点时,可以通知外层做一个替换,即重新做一个$mount挂载在celldom上,将el-input换成span,为了进一步理解,我们这里也可以使用span的继承方式,用new来实例化,详见下文完整代码完整代码目录结构threeC--data.js--input.vue--span.vuethree.vue为继承el-input组件input.vue exportdefault{props:{单元格值:{类型:字符串|Number,默认:"",},},};统一继承和暴露data.js文件importVuefrom"vue";importdefinedInputfrom"./input.vue";importdefinedSpanfrom"./span.vue";constinputC=Vue.extend(definedInput);constspanC=Vue.extend(definedSpan);exportdefault{inputC,spanC,}使用继承的三个.vue组件