在現代的vue組件庫上實現表格編輯其實不難,它們大都提供了做用域插槽,能夠在插槽內插入input
組件來實現。但這樣作有個弊端,過重了!在幾十上百行的表格內鋪滿input
卡頓幾乎不可避免,並且也很難作到美觀。html
想實現動態編輯功能其實理論上並不難,咱們只需在當前點擊的單元格中渲染出input
,光標離開銷燬這個input
便可vue
這裏藉助 vue自定義指令來實現
由於指令不支持直接數據雙向綁定,參數上設計了value
和input
2個鉤子,一個用來取值,一個用來賦值node
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
這個配置項方便自定義擴展element-ui
<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
來使用antd
v-td-input="{value: () => row.date, input: v => row.date = v }"
相似下面這個例子app
<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
來實現雙擊編輯iview
<span v-td-input="{ type: 'dblclick', value: () => row.date, input: v => row.date = v }" > {{ row.date }} <span>
我測試了比較熱門的幾個vue組件庫,都能正確工做
element-ui
iview
antd-vuedom