vue项目踩坑

  由于上一个小项目写的很次,这一次打算好好地写一个博客系统,最近刚刚结束了管理员的管理端的编写。其中遇到了很多小坑。

  其实只能说自己vue用的不是特别熟练吧。很多问题都有些想当然了,实现起来发现了很多的问题。简单的记录几个我自己认为值得记录的吧。

一、一个很坑的问题,vue在对其中一个目标进行改变的时候,实际上会对模板内部的方法和变量等都进行重新渲染,这样就会导致一个问题。如下

<template>
  <div class="hello">
    <ul>
      <li v-for="item in datas">
        <div :>{{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 :>{{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 :>{{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--------------------------------------------------------