由于上一个小项目写的很次,这一次打算好好地写一个博客系统,最近刚刚结束了管理员的管理端的编写。其中遇到了很多小坑。
其实只能说自己vue用的不是特别熟练吧。很多问题都有些想当然了,实现起来发现了很多的问题。简单的记录几个我自己认为值得记录的吧。
一、一个很坑的问题,vue在对其中一个目标进行改变的时候,实际上会对模板内部的方法和变量等都进行重新渲染,这样就会导致一个问题。如下
<template> <div class="hello"> <ul> <li v-for="item in datas"> <div :style="{fontSize:changsize()}">{{item}}</div> </li> </ul> <input type="text" v-model="tests"> {{tests}} </div> </template> <script> export default { name: 'HelloWorld', data () { return { datas:['one','two','three','one','two','three','one','two','three'], fz:'', tests:'', } }, watch:{ datas(val){ console.log(111); return; } }, methods:{ changsize(){ return (parseInt(Math.random()*15)+10)+'px'; } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
代码如上,如果我在input内部输入内容,这样就会改变了data内部的tests,进而整个模板都进行一次重新渲染。这样就导致我输入一个数据这个字体的大小就全部改变一次。这样就违背了我的初衷,仅仅是想在模板加载的时候赋值一次就可以了!!!以后输入内容的时候不需要改变了。开始还以为能有类似钩子函数的东西来禁止一下。最后发现有点问题。
在网上解决问题的时候找到这样一句话:
每个vue实例都有一个根元素id的属性el,Vue对象通过它来找到要渲染的部分。之后使用createDocumentFragment()方法创建一个documentFragment,遍历根元素的所有子元素,依次劫持并插入文档片段,将根元素掏空。然后执行Vue的编译:遍历documentFragment中的节点,对其中的v-for,v-text等属性进行相应的处理。最后,把编译完成后的documentFragment还给根元素。
这样也就是说其实它实际上是对整体都进行了处理,如果要改变的话可能需要重写一些方法......
那就换一个思路好了,在自己写的代码层面上想办法。
1.当时想的第一个办法是每一次在生成datas(在我得项目里这个数据是从数据库取出来的),就直接生成一个随机的字体大小存储在数据库中。这样加载的时候就可以直接设置了。但是也有坏处。改变了自己的初始设计想法。。。。
2.今天仔细想了一下,想出了一个办法。使用一个变量用来存储模板刷新的时候所生成的字体大小,这样在使用的时候用这个自己定义的数组变量和相应的item的index来进行分辨到底设置哪个字体的大小。代码如下
<template> <div class="hello"> <ul> <li v-for="(item,index) in datas"> {{changsize(index)}} <div :style="{fontSize:font_size[index]}">{{item}}</div> </li> </ul> <input type="text" v-model="tests"> {{tests}} </div> </template> <script> export default { name: 'HelloWorld', data () { return { datas:['one','two','three','one','two','three','one','two','three'], fz:'', tests:'', font_size:[], } }, watch:{ datas(val){ console.log(111); return; } }, methods:{ changsize(index){ if(this.font_size.length!=this.datas.length){this.font_size[index]=(parseInt(Math.random()*15)+10)+'px'; }else{ return; } } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
3.对于上面的方法纯属是属于通过自己的逻辑来进行判断。在methods运行的时候还需要使用if来判断一下。那么根据上一个方法有个优化的方法,我们可以声明一个数组变量,然后不断地push进新的数据进行存储,在赋值的时候依旧使用 数组[index] 这样的形式来赋值,这样就可以了。
<template> <div class="hello"> <ul> <li v-for="(item,index) in datas"> {{changsize()}} <div :style="{fontSize:font_size[index]}">{{item}}</div> </li> </ul> <input type="text" v-model="tests"> {{tests}} </div> </template> <script> export default { name: 'HelloWorld', data () { return { datas:['one','two','three','one','two','three','one','two','three'], fz:'', tests:'', // font_size:[], } }, computed:{ font_size(){ return []; } }, methods:{ changsize(){ this.font_size.push((parseInt(Math.random()*15)+10)+'px'); } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
这样就比较完美的解决了这个问题。当然,我们也可以将存储数据的变量放到data内部,例如我在data内部注释的那行代码一样,但是这样会有一个缺点,浏览器会报错
[Vue warn]: You may have an infinite update loop in a component render function.
这个问题的原因就是如果我们在v-for内部使用方法来改变data内的数据的时候,很有可能会导致无线循环,按照我这种写法当然不会触发,但是毕竟还是有可能的,所以我们还是把变量声明到computed好了。毕竟有个红色的报错提醒看着也是很烦的。
-------------------------------------------------2018-05-03 23:56:14--------------------------------------------------------