博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
让Vue的v-for支持迭代器遍历
阅读量:6880 次
发布时间:2019-06-27

本文共 2697 字,大约阅读时间需要 8 分钟。

事情的缘由

在写一个项目的时候希望使用Map来进行遍历,然后我取出了Map的keys,keys是一个Map Iterator(迭代器,ES6引入的Symbol.iterator)类型,这时我尝试使用v-for来对迭代器进行遍历,当然我的期望是能够遍历出来。 我们都知道vue的v-for提供了两种遍历方式,

v-for="item in items"v-for="item of items"复制代码

而js中可以使用

for (index in items)for (item of items) // 这种写法支持对迭代器的遍历复制代码

这时我不禁就想,既然如此,v-for当中of的遍历方式应该是支持迭代器的遍历的,但是事实尝试下来是不可以的,那么为什么不可以呢,然后就去翻查了一下Vue的源码,从中找到了这么一段代码。

/** * Runtime helper for rendering v-for lists. */function renderList (  val,  render) {  var ret, 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)) {    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)._isVList = true  }  return ret}复制代码

我尝试在该段代码中打上了断点,然后发现迭代器本身是一个Object类型(ES5没有Symbol),但是Map IteratorObject.keys(val)则是一个空对象[],一个空的keys,所以此处不会产生遍历然后进行render

作死的开始

既然没有判断出是一个Iterator那么我就添加一个判断,由于刚开始以为不能使用ES5以上的语法,修修改改了好多次,写出了如下的代码,其实这里可以判断类型是否为Symbol.iterator

...  } else if (isObject(val)) {    keys = Object.keys(val)    if (keys.length === 0 && val.toString().indexOf('Iterator') > -1) { // 可能是个迭代器      ret = []      i = 0      while (true) {        if (typeof val.next !== 'function') {          break        }        var next = val.next()        if (next.done) {          break        }        ret.push(render(next.value, i++))      }    } else {      ret = new Array(keys.length)      for (i = 0, l = keys.length; i < l; i++) {        key = keys[i]        ret[i] = render(val[key], key, i)      }    }  } ...复制代码

Symbol类型有个方法是Symbbol.toStringTag

Symol.toStringTag

A string value for the default description of an Object. Used by
Object.prototype.toString()

查阅资料看到了这么一段话,那么我就是用toString方法去取出迭代器的description然后使用indexOf去判断是否包含Iterator来区分是不是一个迭代器。

这里使用了while却没有使用for...of的写法, 由于修改的是dist的文件所以不敢尝试ES5+的写法。 然后一切都看起来很完美,但是运行的时候却走到了handleError(e, vm, "render") 一个ERROR分支...百思不得其解...
经过了N轮的断掉调试,我终于定位了到问题的所在。
由于测试的时候是基于项目做的,项目用的ElementUI,其中用到了form组件,层层定位发现是v-model的值为空造成的Error,然后写了一份简单的v-for发现竟然真的可以了。

template...
{
{item}}
script...data () { return { iterator: this.getIterator() }},methods: { getIterator () { let map = new Map() map.set('title', '') map.set('value', '') return map.keys() }}output...titlevalue复制代码

总结

虽然我在Vue上做了一个ES5+的尝试不知道合不合理,但是在这个探索的过程中学到了很多,希望能对大家有所帮助。

其中了解了Symbol类型究竟是个怎样的类型,了解了迭代器的实现,实践了断点定位问题等等...一个晚上的付出没白费,还是比较欣喜的。

End

I'm 一个渴望成长的码农

转载地址:http://oufbl.baihongyu.com/

你可能感兴趣的文章
微信小程序自定义组件
查看>>
我的友情链接
查看>>
zookeeper报错问题
查看>>
Linux新建文件和目录
查看>>
ACM图灵奖
查看>>
windows 2008 r2 远程桌面一个用户多登录配置
查看>>
我的友情链接
查看>>
在Android Library的Module中按渠道依赖
查看>>
对javascript匿名函数的理解(透彻版)
查看>>
使用virtualbox安装centos6的内置无线网卡桥接设置
查看>>
java调用http接口(HttpURLConnection的使用)
查看>>
java代码内,获得jsp产生的html
查看>>
jquery.validate remote 和 自定义验证方法
查看>>
hibernate使用sql查询
查看>>
二叉树(2)——遍历的非递归实现
查看>>
OS X 键盘快捷键
查看>>
linux下vi命令大全
查看>>
设计模式之四:访问者模式
查看>>
加密和解密
查看>>
python使用.proto文件生成service接口失败
查看>>