绑定Class和Style

v-bind指令可以绑定任意常规类型的变量,而vue对classstyle样式的绑定做了一定的优化,绑定它们时还可以绑定数组、对象类型的变量。

<!-- class 绑定 -->
<div :class="{ red: isRed }"></div><!-- 此处isRed根据是否真值控制red类是否启用 -->
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">
<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<!-- 可以绑定多个值,针对提供多前缀的属性,浏览器不支持的前缀将不会被渲染(vue还支持自动添加前缀) -->
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

动态绑定的样式可以与常规的classstyle属性共存。

计算属性和侦听器

计算属性

虽然模版语法支持js表达式,但是它并不适用复杂计算式,如果需要用到复杂计算时我们可以用组件的methods去实现,而Vue还提供了一个计算属性让我们专门用来做这样一件事。先来看下示例:

<h1>{{ tips }}</h1>
<div>{{divMsg}}</div>
<div>{{divMsg}}</div>
<div>{{divMsg}}</div>
<div>{{divMsg2()}}</div>
<div>{{divMsg2()}}</div>
<div>{{divMsg2()}}</div>
export default {
  name: "Demo",
  data() {
    return {
      tips: 'this is a demo data'
    }
  },
  methods: {
    divMsg2() {
      // ... do something
      console.log('tips has method.');
      return this.tips + ' by method.'
    }
  },
  computed: {
    // 计算属性的getter函数
    divMsg() {
      // ... do something
      console.log('tips has computed.');
      return this.tips + ' by computed.'
    }
  }
}

可以看到,computedmethods看上去几乎一样,那么不一样的点是什么呢?VueJava比较像,按Java解释就是methods是类里定义的常规函数,computed里定义的是类里的属性和它的settergetter函数,只是属性可以不写,可以只写个getter函数,就像上面的方式一样。完整定义方式如下:

// ...
computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

还有一点是computed会用到缓存,计算属性只在相关响应式依赖发生改变时它们才会重新求值。上面的示例可以看到divMsg函数的仅被调用了一次,而实际上有3个地方被用到,所以剩下2次都是用的缓存。而divMsg2则是用到了3次也就被调用了3次,如果是在一个数据比较多的循环中这样用,那将会造成很多的开销。

计算属性会将计算结果放到页面缓存中,只要这个属性没有发生变化就不会更改缓存。

侦听器

上面的计算属性虽然已经很好用了,但是总有需要自己控制什么时候修改数据的需求,Vue也提供了一个更加通用的方式watch。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

下面是Vue官方的提供的一个示例:

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question" />
  </p>
  <p>{{ answer }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script>
  const watchExampleVM = Vue.createApp({
    data() {
      return {
        question: '',
        answer: 'Questions usually contain a question mark. ;-)'
      }
    },
    watch: {
      // whenever question changes, this function will run
      question(newQuestion, oldQuestion) {
        if (newQuestion.indexOf('?') > -1) {
          this.getAnswer()
        }
      }
    },
    methods: {
      getAnswer() {
        this.answer = 'Thinking...'
        axios
          .get('https://yesno.wtf/api')
          .then(response => {
            this.answer = response.data.answer
          })
          .catch(error => {
            this.answer = 'Error! Could not reach the API. ' + error
          })
      }
    }
  }).mount('#watch-example')
</script>

参考文档