[Источник] Дубительское понимание глубины V-для

Vue.js

Недавно я читал исходный код элемента, но есть много внутренних элементов.this._lметод,elementНе могу найти в исходниках, проверил, оказалось метод внутреннего списка рендеринга Vue

Местоположение источника, код не длинный, его можно прочитать

Три полезные функции

isDef

isDef isDefined — это аббревиатура, которая, в свою очередь, isUndefined, в любом случае, это для того, чтобы убедиться, что это не undefined

function isDef (v) {
  return v !== undefined && v !== null
}

isObject

isObject, который в основном различает примитивные значения и объекты

function isObject (obj) {
  return obj !== null && typeof obj === 'object'
}

hasSymbol

Используется для определения того, поддерживает ли текущая хост-среда собственные символы Symbol и Reflect.ownKeys. Сначала определите, существуют ли Symbol и Reflect, и используйте функцию isNative, чтобы убедиться, что Symbol и Reflect.ownKeys являются собственными определениями.

var hasSymbol =
  typeof Symbol !== 'undefined' && isNative(Symbol) &&
  typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys);

/* 判断是否是内置方法 */
function isNative (Ctor) {
  return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}

renderList

существуетsrc/core/instance/render-helpers/index.jsВ методе installRenderHelpers метод renderList копируется вtarget._l,Прямо сейчасthis._l = renderList

Логика кода очень понятна, разделена на четыре случая (вы можете думать о val как о значении, которое является v-for)

Val — это массив или строка

ret = new Array(val.length)
for (i = 0, l = val.length; i < l; i++) {
  ret[i] = render(val[i], i)
}

Вал - это число

Он даже поддерживает номер! !

ret = new Array(val)
for (i = 0; i < val; i++) {
    ret[i] = render(i + 1, i)
}

val — это объект

  • Поддерживающие символы и содержащие итераторы

Symbol.iterator определяет итератор по умолчанию для каждого объекта Среди встроенных типов Array, String, Map, Set, TypedArray и Object нет.

Итак, чтобы иметь возможность использовать итераторы, мы можем сами определить итератор, пример кода:

const obj = {
  age: 1,
  name: 'liu',
  [Symbol.iterator]: function*() {
    let properties = Object.keys(this)
    for (let i of properties) {
      yield [i, this[i]]
    }
  }
}

const res = obj[Symbol.iterator]()
console.log('res', res.next())

Таким образом, заказ, если у вас есть спрос на пользовательские перечислены порядок слов, вы можете настроить итератор для прохождения определения значения

ret = []
const iterator: Iterator<any> = val[Symbol.iterator]()
let result = iterator.next()
while (!result.done) {
    ret.push(render(result.value, ret.length))
    result = iterator.next()
}
  • Когда символ не поддерживается

Эта ситуация относительно проста, создайте массив атрибутов объекта с помощью Object.key, а затем пройдите его.

keys = Object.keys(val)
ret = new Array(keys.length)
for (i = 0, l = keys.length; i < l; i++) {
    key = keys[i]
    ret[i] = render(val[key], key, i)
}

значение не определено

возвращает пустой массив

if (!isDef(ret)) {
    ret = []
}

PS: Хотя я думаю, что эту ненормальную ситуацию следует поставить на первое место, это личная привычка кодирования, и это не большая проблема.

Суммировать

  • v-for может перемещаться по числам и строкам
  • Вы можете настроить итератор объекта для реализации пользовательского порядка списка.
  • TypeArray имеет итераторы, то есть v-for может отображать массивы классов
  • Обработка исключений выполняется в v-for, поэтому, когда вы передаете значение, не принадлежащее Array, String, Number, Object, v-for отображает пустой массив.

исходный код

import { isObject, isDef, hasSymbol } from 'core/util/index'

/**
 * Runtime helper for rendering v-for lists.
 */
export function renderList (
  val: any,
  render: (
    val: any,
    keyOrIndex: string | number,
    index?: number
  ) => VNode
): ?Array<VNode> {
  let ret: ?Array<VNode>, i, l, keys, key
  if (Array.isArray(val) || typeof val === 'string') {
    ret = new Array(val.length)
    for (i = 0, l = val.length; i < l; i++) {
      ret[i] = render(val[i], i)
    }
  } else if (typeof val === 'number') {
    ret = new Array(val)
    for (i = 0; i < val; i++) {
      ret[i] = render(i + 1, i)
    }
  } else if (isObject(val)) {
    if (hasSymbol && val[Symbol.iterator]) {
      ret = []
      const iterator: Iterator<any> = val[Symbol.iterator]()
      let result = iterator.next()
      while (!result.done) {
        ret.push(render(result.value, ret.length))
        result = iterator.next()
      }
    } else {
      keys = Object.keys(val)
      ret = new Array(keys.length)
      for (i = 0, l = keys.length; i < l; i++) {
        key = keys[i]
        ret[i] = render(val[key], key, i)
      }
    }
  }
  if (!isDef(ret)) {
    ret = []
  }
  (ret: any)._isVList = true
  return ret
}