最近在阅读element源码的,可是element内部有不少this._l
方法,element
源码里面也找不到,查了一下,原来是vue的内部渲染列表的方法vue
源码位置,代码不长,能够一读git
isDef是isDefined的缩写,反过来就是isUndefined,反正就是看它是否是undefinedgithub
function isDef (v) {
return v !== undefined && v !== null
}
复制代码
isObject,主要区分原始值和对象数组
function isObject (obj) {
return obj !== null && typeof obj === 'object'
}
复制代码
用来判断当前宿主环境是否支持原生 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())
}
复制代码
在src/core/instance/render-helpers/index.js
的installRenderHelpers方法中,renderList方法复制给了target._l
,即this._l = renderList
工具
代码逻辑很清晰,分四种状况(你能够把val看做被v-for的那个值)ui
ret = new Array(val.length)
for (i = 0, l = val.length; i < l; i++) {
ret[i] = render(val[i], i)
}
复制代码
居然还支持 number !!this
ret = new Array(val)
for (i = 0; i < val; i++) {
ret[i] = render(i + 1, i)
}
复制代码
Symbol.iterator 为每个对象定义了默认的迭代器,内置类型中,Array,String,Map,Set,TypedArray而Object没有编码
因此为了可以使用迭代器,咱们能够本身定义一个迭代器,示例代码:spa
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: 虽然我以为这种异常状况应该置于最前,属于我的编码习惯,问题不大
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
}
复制代码