从项目一个需求,谈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做些赋值改写数据的操作