VueStudyNote
VueStudyNote copied to clipboard
20 实现双向绑定v-model
其实就是把x-model指令生成的渲染函数改成下面这样生成的一样即可。
<input :value="name" @input="if($event.target.composing)return;name=$event.target.value.trim()"/>
实现
修改ast2renderstr代码
/**
* 解析指令
* @param {*} node
*/
function getDirectiveStr(node: any) {
let dirs = node.directives
let str = '';
if (dirs && dirs.length > 0) {
str += 'directives:['
// why not use for..in, see eslint `no-restricted-syntax`
for (let i = 0; i < dirs.length; i++) {
const dir = dirs[i]
// 把x-model转换为
// <input :value="name" @input="if($event.target.composing)return;name=$event.target.value.trim()"/>
if (dir.name == 'x-model') {
parseModel(node, dir)
continue
}
else if (alreadyDeal(dir.name)) {
continue
}
str += '{'
for (let key in dir) {
str += JSON.stringify(key) + ':'
const val = dir[key]
// 把value的值修改为表达式,render的时候就可以计算
if (key == 'value') {
// 如果有value(表达式)
if (val) {
str += `(${val}),`
}
// 没有表达式,直接赋值一个true即可。
else {
str += 'true,'
}
} else {
str += JSON.stringify(val) + ','
}
}
str += '},'
}
str += '],'
}
return str
}
function alreadyDeal(dirname: string): boolean {
return dirname == 'x-if' || dirname == 'x-else'
}
// FIXME 这里只处理了Input,还有其他的类型
// 把x-model转换为
// <input :value="name" @input="if($event.target.composing)return;name=$event.target.value.trim()"/>
function parseModel(node: Object, dir: Object) {
let attrs = node.attrsMap || (node.attrsMap = Object.create(null))
attrs[':value'] = dir.value
attrs['@input'] = `if($event.target.composing)return;${dir.value}=$event.target.value.trim()`
}