1. 程式人生 > 實用技巧 >從專案一個需求,談vue的render的一次實際應用

從專案一個需求,談vue的render的一次實際應用

需求:

後端返回一個欄位,欄位會包含各種字串以及checkArr,需要把這個欄位渲染成html片段,其中如果遇到□ ,自動變為checkbox 的標籤,並根據checkArr裡的值設定對應預設值,看到(數字)轉為input標籤數字,且重新更改input時候,有對應的事件。

因為有字串需要轉為html標籤且有後續的對應事件函式,所以直接v-html不太方便,嘗試思考render函式處理

實現原則:低耦合,可拓展,可支援不侷限□變為checkbox,還可拓展其他支援,比如○轉為radio,□,○的位置可任意位置

程式碼如下


export const generateTpl = {
number: (opt) => {
const tpl = `<input type='number' class='hse-number' min='0' value="${opt.value}"/>`
if (opt.disable) {
return generatorHTML(tpl, 'input', { disabled: true })
}
return tpl
},
checkbox: (opt) => {
const tpl = `<input type='checkbox' class='hse-checkbox' value="${opt.value}"/>`
if (opt.disable) {
return generatorHTML(tpl, 'input', { disabled: true })
}
return tpl
},
text: (opt) => {
const tpl = `<input type='text' class='hse-text' value="${opt.value}" placeholder="請輸入"/>`
if (opt.disable) {
return generatorHTML(tpl, 'input', { disabled: true })
}
return tpl
}
}

export const generatorHTML = (tpl, tag, attr = {}) => {
const node = new DOMParser().parseFromString(tpl, 'text/html') //DOMParser可以直接把html片段轉為node節點
const tagName = node.getElementsByTagName(tag)[0]
  Object.keys(attr).forEach((key) => {
tagName.setAttribute(key, attr[key])
})
return node.getElementsByTagName(tag)[0].outerHTML
}


render(h) { let text
= this.option.tpl4f || this.option.zhuyaoanquancuoshi //這個是後臺返回的需要轉換的欄位 const checkBoxStr = String.fromCharCode(9633) // □ 用charCode檢測特殊字元,因為charCode是最準確的 const checkBoxRegExp = new RegExp(checkBoxStr, 'g') const numberRegExp = /(\d*)/g let res if (text.indexOf(checkBoxStr) !== -1) {
this.hasCheckBox = true const splits = text.split(checkBoxStr) const checkBoxValues = splits.slice(1) this.firstMsg = splits[0] let num = 0 while ((res = checkBoxRegExp.exec(text)) != null) { text = text.replace(res, generateTpl.checkbox({ value: checkValue(checkBoxValues[num]), disable: false || checkEdit(), })) num++ } } while ((res = numberRegExp.exec(text)) != null) { this.hasNumber = true const target = res[0] const num = +target.substring(1, target.length - 1) || 0 text = text.replace(res, generateTpl.number({ value: num, disable: false || this.hasCheckBox || checkEdit(), })) } return h('div', { class: { 'hse-field-wrapper': true, }, domProps: { innerHTML: text, }, on: { change: this.handleChange, }, }); },



注意點:每個資料model變化時候,render都會觸發,儘量少在render做些賦值改寫資料的操作