VueStudyNote icon indicating copy to clipboard operation
VueStudyNote copied to clipboard

20 实现双向绑定v-model

Open xwjie opened this issue 6 years ago • 0 comments

其实就是把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()`
}


xwjie avatar Jan 22 '18 15:01 xwjie