目录
- 1.阻止事件点击
- 2.v-bind:src时图片加载问题
- 3.props传值问题
- 4. .native原生事件
- 5. vue-router 懒加载
- 6. vue项目里使用阿里的 iconfont
- 7. vue 父组件调用子组件方法并接收参数 $emit
- 8. vue watch 监听(父子组件在同一个页面里,数据变化时组件没有重新渲染情况下可用)
- 9. vue mixins
- 10. iview form表单验证number类型
- 11. iview menu菜单栏修改时遇到的问题
- 12. vue 附件上传
- 13. 自己写的toast组件
- 14. vue 防止跳转到不存在的页面
- 15. iview form表单时间验证,类型不同会报错
- 16. vue $el一次小踩坑
- 17. vue 升级后 nextTick 源码变化
- 18. 浅析Vue 中的patch和diff(上)
- 19. Vue2.0 v-for 中 :key 到底有什么用?
- 20. iview Modal组件中使用Form组件,验证不通过但是却会关闭Modal
- 21. Tabpane布局切换发现包含时间的属性只在第一次渲染,之后切换Tabpane时间不变
- 22. keep-alive 缓存页面防止重绘
- 23. vue data里面的对象添加子属性的问题
- 24. vue 登录页监听回车事件
1.阻止事件点击
例子:
这里的click.stop
即可阻止事件执行。
2.v-bind:src时图片加载问题
js
一开始百思不得其解为什么:src
动态加载不了图片呢,关键还没有报错,后来在知乎看到了答案,需要加require
。这个跟webpack
有关,需要详细了解下。网上有人解释道:图片的动态引入需要当做一个模块来进行打包 不然webpack会默认为字符串的。
3.props传值问题
直接看示例:
https://github.com/lizhongzhen11/myStudy/blob/master/vue/props.vue
https://github.com/lizhongzhen11/myStudy/blob/master/vue/components/childProps.vue
4. .native原生事件
https://segmentfault.com/q/1010000007896386/a-1020000007896602
最近开发后台管理系统项目,环境是苍老师搭的。抽空看了下苍老师搭的环境配置,发现他写的路由和通过vue-cli
构建后默认的路由不一样!
首先,他在router
文件夹下有两个js
,一个是默认的index.js
,还有一个是他定义的router.js
,以前没大注意,在他的环境中路由都是写在router.js
里面的,但是一个经过vue-cli
构建的项目,默认路由是下面这种写法:
但是,苍老师搭建的环境不是这样写的。苍老师环境中的index.js
:
router.js
:
他主要用到了路由懒加载,看https://router.vuejs.org/zh-cn/advanced/lazy-loading.html 。为什么采用这种方式呢?
当采用默认的路由方式,那么组件会先全部在
index.js
头部import
进来才会去加载,页面少就算了,如果页面多,那么加载速度明显会变慢;而采用懒加载方式,当跳转到某页面时才会去加载它对应的组件,这样会大大提高加载速度。
在开发过程中需要用到iconfont,由于在上一个项目中用到过,所以有点印象。但是!!!那个项目的环境全是苍老师配置的,这个项目我想自己配置锻炼下,结果就悲催了。
一开始,进展很顺利,看 https://www.cnblogs.com/chinabin1993/p/8184296.html 即可。可惜,当走到最后一步import ./iconfont/iconfont.css
时,报错了,说找不到./iconfont/iconfont.svg?t=1524893607035 in...
???那个链接上也有展示,不过他说把css-loader
装一下就好了。不过我是用的vue-cli
搭建的,这个css-loader
貌似一开始就装好了。这样我就很郁闷了!!!
我百度了起码2小时,愣是找不到原因,后来索性重新把下载下来的iconfont
文件全部再拷贝进去,成功了!!!卧槽他大爷!!!为什么?因为我一开始是一个文件一个文件的拷贝进去的,我当时想某些文件可能没用,但是拷贝途中有可能遗漏了某个文件,操蛋啊,自作孽啊。。。
7. vue 父组件调用子组件方法并接收参数 $emit
回到目录
直接看示例:
|
|
父组件html
子组件
子组件html
8. vue watch 监听(父子组件在同一个页面里,数据变化时组件没有重新渲染情况下可用)
回到目录
开发列表页和列表详情页时,由于老板要求这两个页面写在一个路由里,这样可以减少路由切换,所以采用了iview
框架里的Tabs
组件,该组件其实是利用css
进行切换的,所以没有涉及到组件的重新挂载。
当我用props
进行父子组件传参时,发现当父组件数据改变后,子组件数据没有任何变化!我习惯性的在mounted()
里面打印,但是如果组件没有重新挂载过,那么mounted()
只在初始化渲染时有用!!!所以这时候在mounted()
里面无论如何也无法得到父组件改变后传过来的数据了!!!
看例子,父组件:
父组件js:
子组件js:
项目中有多个相似的页面及操作方法,所以可以使用mixins
简化开发。但是在使用中没有仔细阅读文档,踩了个小坑。mixins
有点类似java中的覆盖。如果组件中存在与mixins
同名的属性或方法,那么会使用组件中定义的属性和方法覆盖mixins
里面定义的。
https://cn.vuejs.org/v2/guide/mixins.html
10. iview form表单验证number类型
回到目录
看 https://segmentfault.com/q/1010000010333755?sort=created
在后期测试发现,如果将number
类型的验证按照上述分成两步来写,那么刚进入页面时即使该输入框内有默认值0,还是会报红,后来发现将验证规则合在一起写不会有这个问题,但是,把默认值删了,直接传空的话就会有新问题了,因为Number('') === 0
,可以改用parseFloat()
,如下:
其实iview
的菜单栏挺不错的,但是老板要求当屏幕缩放时,所有菜单都能显示,除非浏览器高度小于所有菜单高度,否则的话必须全部显示!语言表述可能不大准确,上图:
就是要做成如上图的样子。可以看到,当浏览器缩放到一定程度时,政务办公下面的子菜单只显露了一个通讯录,其实这样是不大美观的,奈何老板需求这样,那么只能做了。
一开始还好,给子菜单里加了overflow-y: auto;
,然后在 https://www.lyblog.net/detail/314.html 找到了修改进度条样式的方法(有兼容性),接下来利用浏览器显示高度 - 父菜单总高度(这个是固定不变的) = 子菜单所在块高度,然后找到子菜单所在块改style.height
不是很完美吗?
可惜,想的太好,iview
封装过的Menu
组件很好,但是我也无法直接去操作子菜单所在的块,只能通过ref
以及name
等通过数组下标的形式慢慢找到对应的ul
,没错,是一个拥有.ivu-menu
class的ul
,虽然写的不优雅,但起码取到了啊,这时候配合window.onresize()
完美完成需求。心里暗自高兴,结果,很快发现bug了。
页面刚加载以及点击切换时不起作用!!!我在mounted()
里面调用了该方法,同时也在iview
提供的监听菜单展开关闭的方法中调用了改变ul.ivu-menu
高度的方法,但是,不起作用!!!
纠结了很长时间,用过this.$nextTick()
以及在其内部调用setTimeout
都没作用,一气之下看iview
的源码,在https://github.com/iview/iview/blob/2.0/src/components/menu/submenu.vue里:
如上所示,第一个li
代表每个父菜单,父菜单内部包含一个div
与一个ul
标签(),div
用来放父菜单标题,关键在于ul
标签,iview
内提供的MenuItem
就是插在这个ul
标签内的。现在,我想改的就是ul
的样式,不过很抱歉,它没给我提供api。。。
在仔细观察源码后依然无法解决,遂问了苍老师,苍老师说加个setTimeout
看看,我心想我用过啊,结果直接在mounted()
里加果然有效果,不需要在this.$nextTick()
里面加,但是由于我写得渣,采取的是直接style.height
形式,一上来连过渡效果都没有,很糙,本想着加个过渡效果,发现依然没用。
最后,只好把MenuItem
组件注释掉,自己用ul li
重写,当然写在MenuItem
位置,这样iview
里面的Menu
以及Submenu
组件还有name
属性等就可以直接用了。
我改写的,
老板又又又改需求了!!!难怪程序员都看产品不爽
老板说,有的模块下只有几个菜单,就不要跟其他模块固定同样的高度了,子菜单多的还按以前来。不知你们听懂了没,我截个他需要的图(忙了至少两个半小时才搞定)
如上图,第一个模块下只有两个菜单,比如在我的电脑上,算出来的固定高度是408px
,第一个模块两个菜单肯定用不了这么大的高度,所以老板只想显示这两个菜单高度就好了,而第二张图代表第二个模块下的子菜单,其实有15个子菜单,但因为超过408
的固定高度了,所以这里只显示刚好达到408px
的子菜单,其他的通过滚动条可以查看。
好了,需求讲明白了,无非就是在原来基础上计算价格判断,当子菜单高度之和 < 固定高度的话,该模块展开后的高度应该 === 子菜单高度之和,其实不难,我很快实现了:
但是,结束了吗???如果这么容易就好了,真的fuck啊!
测试时发现,当我切换时,其他菜单展开时不够平滑,对用户不友好,更关键的是,默认展开第一个模块吧,然后我打开最后一个模块(第一个模块自动关上),重新切换到第一个模块时,第一个模块高度竟然和最后一个模块一样高!!!我蒙了???可是当我关闭第一个菜单后再度打开就好了???are you kidding me???
我不断的console
去打印查看,发现,当我代码里对this.diff
进行赋值时,影响到了iview
里面Menu
组件了,该组件提供了@on-open-change
方法,默认接受被打开的菜单编号,当我改变this.diff
时,@on-open-change
方法中的name值不对了!!!
正常情况,打开菜单,@on-open-change="openchange"
对应的openchange(name)
中的name应该是打开菜单的编号数组啊,可是,我这里竟然完全相反,what a fuck !!!是的,我打开一个菜单,控制台打印
???这TM不应是关闭菜单才会打印这个吗,我明明是打开菜单啊!!!我可以贴上代码:
经过我不断尝试,确定问题就出在我给this.diff
重新赋值这里,由于我这里采用的是computed
计算属性来改变高度,但是现在看来,它变化有点慢,这应该是异步的原因,但是得解决啊,后来我想了最糙的办法,直接加ref
,放弃计算属性,然后改写controlHeight
:
虽然解决了这个问题,但是我得真的理解,不然没有进步。所以我去看源码了:https://github.com/iview/iview/blob/2.0/src/components/menu/menu.vue#L119
看了源码发现,在
updateOpenKeys
内部多次用到了findComponentsDownward
方法,而该方法又用到了reduce
方法并且会递归调用自身,这样无疑是很耗时的,而我切换菜单又很快,这就造成了name
值没有及时改变。个人猜想啊~
12. vue 附件上传
回到目录
自己的: https://github.com/lizhongzhen11/myStudy/blob/master/vue/upload.vue
iview的: https://github.com/iview/iview/blob/2.0/src/components/upload/upload.vue
13. 自己写的toast组件
回到目录
github: https://github.com/lizhongzhen11/myStudy/tree/master/vue/components/Toast
vue
虽然用了一段时间了,但是还没有写过真正意义上通用的组件,之前写得大多是半吊子刚好业务能用罢了。但是在九龙湖项目中发现苍老师对所有调接口报错进行了处理,当调接口报错时他会返回给前台一个空对象,然后利用toast
弹出来,不会出现以前那种整个页面都是后台报错信息的情况,美观了不少,于是,我就好奇的去看看他怎么实现的。
拦截很简单,利用了axios
的interceptors
属性,但是,却让我歪打正着看到了他自己写的拦截报错后弹框显示报错信息的toast
组件,由于和iview
的有点相似,一开始我都没在意过,这次看到了大吃一惊,居然是自己写的,看了他的代码,我居然不会这样写。
这样肯定不行的,所以我自己也尝试去写了下,当然不懂得还是看他的代码了。主要是const ToastConstructor = vue.extend(Toast)
这一步创建构造函数,我竟然不知道!!!其实 https://cn.vuejs.org/v2/api/#Vue-extend 官方示例很明显的提出了创建构造器,我竟然没仔细看,以前都是当java的extend来用的。。。
还有document.body.appendChild(newToast.$el)
这一步需要将刚刚实例化的newToast
添加到body
上,不然怎么刷新页面也看不到的!!!
在做自己搭建的项目中偶然发现,浏览器中输入不存在的路由也可以跳转,只不过页面是空的,立即意识到这是个bug需要解决,好在网上已经有了答案,这个答案在刚接触vue时我还看过,只是没能实践过,很简单的:
这时,我突然想到九龙湖项目里也有用到过,但是我没在意过,现在回去头去看,果然用到了,还顺带加上了iView.LoadingBar.start()
这段代码,这个一看就知道是iview
的组件方法,其实就是页面加载进度条,官方也给出了示例。不过九龙湖里还打算在页面跳转中做权限验证,但是目前还没开发完毕。
15. iview form表单时间验证,类型不同会报错
回到目录
开发九龙湖项目时,发现后台一开始传过来的是new Date()
类型,而页面上需要展示yyyy-MM-dd HH:mm:ss
,所以所性后台直接做了转换,传给前台需要的格式。但是利用iview
的form
表单验证发现了问题,第一次修改保存是ok的,但是第二次修改同一条数据,发现控制台报value.getTime is not a function,这就很奇怪了,后来不断console.log()
发现第一次输出是new Date()
类型,但是第二次输出是yyyy-MM-dd HH:mm:ss
的字符串类型,两次类型不一致了,解决方法就是保持类型一致。
可以看:https://segmentfault.com/q/1010000012129675
以及:https://github.com/ElemeFE/element/issues/8020
一开始在iview Form
组件内部插入了一个Card
组件,并设置了ref
属性,然后通过点击事件打印this.$refs.workflow.$el.className
有输出,但是后来因为需求变更,将Card
组件移出到与Form
组件同一级别后,发现原先的方法报错,console
后发现this.$refs.workflow.$el
报错,没有$el
属性,然后直接打印this.$refs.workflow.className
就能得到值了。
简直amazing
!明明ref
属性是加在Card
组件上的,为何改变Card
组件位置取值方法就要改变呢?
17. vue 升级后 nextTick 源码变化
回到目录
看 https://juejin.im/post/5a1af88f5188254a701ec230
18. 浅析Vue 中的patch和diff(上)
回到目录
https://github.com/kaola-fed/blog/issues/259
https://github.com/kaola-fed/blog/issues/263
接触vue有一段时间了,以前一开始认为只要数据改变vue就会重新渲染页面,但是后来听同事说数据改变,vue并不会立即重新渲染,想想也是,数据一变就立即重新渲染,那么性能注定是极差的!但是我一直不大懂vue是怎么进行重新渲染的,直到最近接触了macrotask
,microtask
,event loop
以及nextTick
源码解析等知识,才大致了解。
原来数据都会放在
watcher
里面监听,当数据变化时,更新watcher
数组里面的数据,然后统一放到nextTick
去更新。nextTick
内默认使用microtask
,但是在某些情况下会强制使用macrotask
。
19. Vue2.0 v-for 中 :key 到底有什么用?
回到目录
https://www.zhihu.com/question/61064119
20. iview Modal组件中使用Form组件,验证不通过但是却会关闭Modal
回到目录
开发时发现,在Modal
组件中使用Form
组件时,给Form
组件内加上验证,点击确认按钮时虽然验证生效了但是Modal
依然关闭了,这样使用效果并不好,应该是验证不通过时Modal
不会关闭让用户继续填写才对,填写完应该可以再度点击确认按钮才对。
后来在iview
官方发现Modal
组件提供了loading
属性,当设置为true
时,点击确认按钮不会关闭Modal
,但是,之后也不能点击确认按钮了。这样依然不行,没有达到我的期望。
之后在 https://github.com/iview/iview/issues/3079 中也看到相似问题,那位朋友采用了setTimeout
来解决,我也尝试了一下,可以解决。但是当快速点击确认按钮时依然会关闭Modal
,这样依然不完美。
不过,想到最近有看过macrotask
等相关知识,加之vue源码中用到了MessageChannel
,所以我也就尝试一下,果然解决了,但是有兼容性问题。
21. Tabpane布局切换发现包含时间的属性只在第一次渲染,之后切换Tabpane时间不变
回到目录
首先说一下,这个问题是苍老师发现并解决的,我从来都不知道存在这个bug,一点都不细心啊!
由于后台管理系统里有太多列表页,而列表页也有相对应的详情页,为了简化开发任务,同时减少页面重绘优化性能,所以采取了iview
的Tabs
组件,列表详情页成为列表页的子组件,改变name
值即可切换,同时具有很高的通用性。这样做确实带来了很多方便,但同时也有一些小问题。
比如这次苍老师发现的,第一次进入详情页,时间没什么问题,回到列表页后在该页面驻足一段时间后,发现计算机时间已经过了好几分钟,但是列表详情页的时间居然是第一次进入详情页的时间,也就是说再度进入页面时间没有更新。
其实仔细想想也能理解,因为此时列表详情页是列表页的子组件了,子组件先于父组件渲染的,它们在同一个路由,当切换到列表详情页后并不会再度渲染,所以时间当然不变化了。
怪自己不细心,写完一个页面看数据都有了能对接了就认为ok了,没有关注数据是否合适的问题。
不过苍老师解决的方法也很巧妙,利用了函数式编程的思想,即将拥有时间属性的属性写成函数,然后每次切换Tabpane
时调用函数就相当于执行一次new Date()
,真的巧妙。因为如果我来解决,我可能会通过遍历找拥有时间的属性然后重新赋值,那样太麻烦了。
附上例子:
https://cn.vuejs.org/v2/api/#keep-alive
开发后台管理系统时经常遇到列表和列表详情页,有一个需求是这样的:当在 A页面对应的详情页时点击菜单跳转至B页面,然后在点击菜单回到A页面对应的详情页,而不是回到A页面的列表页,以减少用户操作。
后来苍老师做好了,我抽了时间翻遍了代码愣是没看到他在哪里写得,遂侥幸百度,得知<keep-alive></keep-alive>
内置组件就是用来缓存阻止浏览器重绘的。老实说,我第一次看Vue官方文档时看过,但由于以前没用过,所以没想起来。。。
用法很简单,在路由跳转加上该组件即可:
其实看过官方文档并且写代码有意识的人基本上不会觉得这是什么大问题,但是,如果是去看他人写得代码,并且略微有点复杂的情况下,接手者很有可能不能立即找到问题所在。。。
最近在做的项目中有用到附件上传,同事做了一个组件,其实项目上大部分组件都是他封装的,挺厉害的。因为不少页面用到该功能,所以我就按照他在其他页面上引用的方式一样引入并使用,但是,当我上传成功后发现附件table
面板里没有刚刚上传的文件信息,反观他的示例页面却有,很奇怪。想直接问他的,但是考虑到自己成长以及没有看过他这个组件代码问题,想学习一下顺便自己发掘问题所在,遂自己去查看他的组件代码。
组件不复杂,3个.vue
文件以及一个config.js
,其中一个是基础模板,另两个继承自它且侧重点不同,分为:attachuploadlist.vue
和imageuploadlist.vue
,看名字就明白了。配置文件里放的是table
的表头,且用到了render
函数。该组件依赖于iview
,不会写table
里面的render
函数的同学可以去iview
的官方文档上找。
接下来我将这些文件内的代码过了一遍,大致了解过程了,然后一处处去写console
调试,最终发现在上传文件成功后关闭Modal
框时出现了问题(没错,用的iview
的Modal
),config.js
内的表头column
中定义的render
方法没有调用,这我就很奇怪了。。。他也没在示例页面上做什么操作啊,怎么他能调用我不行呢?
思考许久后,我还是决定去问同事了,后来同事说你看过updateForm()
方法吗?我发誓看过,不就是简单的赋值吗。如下:
后来同事继续点醒我,this.form
是data
里面的对象,不是普通js对象,是隶属于vue的对象,而vue官方文档说过,data
中的对象因为需要被监听的缘故,所以不能直接赋值,而需要通过$set()
方法去设置新属性,但同事这里为了方便,所以只需要将被赋值的属性预先写在data
里面就可以了,而我的问题就是没有在页面data
内预先写下files
属性,导致无法在form
属性中直接添加files
属性以及给它赋值,所以页面上才没有出现文件信息。。。
有些知识点以为很简单,但是稍微一用就可能让人迷失错愕,经验不足!
24. vue 登录页监听回车事件
回到目录
https://segmentfault.com/q/1010000011347642/a-1020000011348067