内容简介:最近在阅读element源码的,但是element内部有很多isDef是isDefined的缩写,反过来就是isUndefined,反正就是看它是不是undefined
最近在阅读element源码的,但是element内部有很多 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 为 Array,或者 String
ret = new Array(val.length) for (i = 0, l = val.length; i < l; i++) { ret[i] = render(val[i], i) } 复制代码
val 为 number
竟然还支持 number !!
ret = new Array(val) for (i = 0; i < val; i++) { ret[i] = render(i + 1, i) } 复制代码
val 为 Object
- 支持Symbol,且含有迭代器的情况
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() } 复制代码
- 不支持Symbol的情况
这种情况比较简单,通过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) } 复制代码
val 没有被定义的情况
返回一个空数组
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 } 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- ThreadLocal源码深度剖析
- SnapHelper源码深度解析
- Injection源码深度解析
- 一文深度剖析 Axios 源码
- 深度解读 ReentrantLock 底层源码
- Golang channel源码深度剖析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。