沐鳴總代平台_一個指令為各大vue組件庫的table組件加上動態編輯功能
寫在前面
在現代的vue組件庫上實現表格編輯其實不難,它們大都提供了作用域插槽,可以在插槽內插入input組件來實現。但這樣做有個弊端,太重了!在幾十上百行的表格內鋪滿input卡頓幾乎不可避免,而且也很難做到美觀。
思考
想實現動態編輯功能其實理論上並不難,我們只需在當前點擊的單元格中渲染出input,光標離開銷毀這個input即可
實現
這裏藉助 vue自定義指令來實現
因為指令不支持直接數據雙向綁定,參數上設計了value和input2個鈎子,一個用來取值,一個用來賦值
import vue from 'vue';
const getTargetEl = (el, nodeName = 'TD') =>
el.nodeName === nodeName ? el :
el.parentElement ? getTargetEl(el.parentElement, nodeName) : undefined;
function createInput(options) {
const input = document.createElement('input');
input.className = options.inputClass || 'td-input';
input.type = options.inputType || 'text';
input.value = typeof options.value === 'function' ? options.value() : options.value;
return input;
}
const targets = [];
function handle(el, binding) {
const options = binding.value || {};
const targetEl = getTargetEl(el, options.nodeName || 'TD');
if (targetEl) {
let target = targets.find(v => v.el === targetEl);
if (!target) {
target = {options, el: targetEl};
targets.push(target);
let inputEl;
targetEl.style.position = 'relative';
targetEl.addEventListener(options.type || 'click', () => {
if (!inputEl) {
inputEl = createInput(target.options);
targetEl.appendChild(inputEl);
inputEl.focus();
inputEl.onblur = () => {
target.options.input && target.options.input(inputEl.value);
targetEl.removeChild(inputEl);
inputEl = undefined;
};
}
});
} else {
target.options = options;
}
}
}
const TdInput = {
inserted: handle,
update: handle,
};
/**
* v-td-input="{value: () => row.name, input: v => row.name = v }"
*/
vue.directive('td-input', TdInput);
代碼寫完了,我們需要給這個input定義樣式,我在createInput的代碼中默認給它加了.td-input這個類,並提供了inputClass這個配置項方便自定義擴展
<style>
.td-input {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding: 0 10px;
box-shadow: 1px 1px 20px rgba(0,0,0,.15);
box-sizing: border-box;
background-color: #FFF;
background-image: none;
border: 1px solid #DCDFE6;
display: inline-block;
outline: 0;
}
.td-input:focus {
border-color: #5FB878!important
}
</style>
使用
在作用域插槽內通過一個可以綁定指令的dom來使用
v-td-input="{value: () => row.date, input: v => row.date = v }"
類似下面這個例子
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="date"
label="日期"
width="180">
<template slot-scope="{row}">
<span v-td-input="{value: () => row.date, input: v => row.date = v }">{{ row.date }}<span>
</template>
</el-table-column>
</el-table>
提供了一個type配置項,指定觸發事件,默認是單擊click,你也可以像下面這樣設置成dblclick來實現雙擊編輯
<span
v-td-input="{
type: 'dblclick',
value: () => row.date,
input: v => row.date = v
}"
>
{{ row.date }}
<span>
另外有一個配置項nodeName用來篩選綁定事件對象,默認是TD,如果想在表頭使用,需改成TH,參考下面element-ui的例子
效果
我測試了比較熱門的幾個vue組件庫,都能正確工作
element-ui
iview
antd-vue
原文:https://segmentfault.com/a/1190000021871839
站長推薦
1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲
2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入
鏈接: http://www.fly63.com/article/detial/8011