表达式解析

sync 修饰符

在这个修饰符的背后,vue 会做两步处理。看下面的代码:

<video :title.sync="aa"></video>

<!-- 上述代码会被转述为以下代码 -->
<video :title="aa.b" @update:title="aa.b = $event"></video>

<!-- 如果是动态属性 -->
<video :[title].sync="aa"></video>

<!-- 上述代码会被转述为以下代码 -->
<video :[title]="aa.b" @update:+(title)="aa.b = $event"></video>
复制代码

在这其中,= 右侧的值主要分为三种情况:

  • a
  • a.b
  • a[b]/a[0]

针对上面的三种情况,会出现不同的处理策略。

处理

处理表达式主要分为两种情况

  • 单值非链式表达式,如 a,b
  • 链式表达式,如:a.ba[b] 此类的表达式
    • 对于链式表达式,需要解析出末尾的表达式,使用 $set 进行响应式处理。防止属性没有进行响应式处理而导致不能正常更新
  • 基本上面两种情况,最终能得到的如下结果:
    • 对于单值表达式会得到 a = $event
    • 对于链式表达式会得到 $set(a, b, $event)
      • 需要注意的是 b 可以是动态值

coding


// 根据值得类型解析出赋值表达式
function genAssignmentCode(value, assignment) {
  const res = parseModel(value);
  if (res.key === null) {
    // 这里说明 value 是 a
    return `${a} = ${assignment}`;
  } else {
    return `$set(${res.exp}, ${res.key}, ${assignment})`;
  }
}

let str, chr, len, index, expressionStartPos, expressionEndPos;

function parseModel(val) {
  val = val.trim();
  len = val.length;
  // 表示没有动态表达式
  // 这里表示 a[b].c 
  if (val.indexOf("[") < 0 || val.lastIndexOf("]") < len - 1) {
    if ((index = val.lastIndexOf(".")) > -1) {
      // 说明是 a.b 这样子的表达式
      return {
        exp: val.slice(0, index),
        key: `"${val.slice(index + 1)}"`,
      };
    } else {
      return {
        exp: val,
        key: null,
      };
    }
  }

  // 说明存在动态表达式 a[b]/a[0]
  str = val;
  index = expressionStartPos = expressionEndPos = 0;

  while (!endOf()) {
    chr = next();
    // 表示 [ 开头的字符串
    if(chr === 0x5B){ // 0x5B === '['
        parserBracket(chr)
    }
  }
  return {
      exp: val.slice(0, expressionStartPos),
      key: val.slice(expressionStartPos + 1, expressionEndPos)
  }
}

function endOf() {
  return index >= len;
}

function next(){
    // 每次读取一个字符
    return str.charCodeAt(++index)
}

function isStringStart (chr: number): boolean {
  // 0x22 代表 "   0x27 表示 '
  return chr === 0x22 || chr === 0x27
}

function parserString(chr){
    const stringQuote = chr // 记录开始字符 "/'
    while(!endOf()){
        chr = next()
        if(chr === stringQuote){
            break
        }
    }
} 

// 解析出中括号中的变量
function parserBracket(chr) {
    let inBracket = 1
    expressionStartPos = index
    while(!endOf()){
        chr = next()
        if(isStringStart(chr)){
            parserString(chr)
            continue;
        }
        if(chr === 0x5B) inBracket++ // [
        if(chr === 0x5D) inBracket-- // ]
        if(inBracket === 0){
            expressionEndPos = index
            break
        }
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享