vue文档里你没捡起来的宝藏

18,950 阅读9分钟

第一次在掘金写文章

  • 不同于在csdn上平日记录给自己和别人解决问题,更想主动分享和讨论
  • 个人能力有限,解决小问题,欢迎讨论指正

第一篇文章想写Vue的原因是刚买了一本《深入浅出 Vue.js 》,所以趁书没到,打算把Vue的文档重新看一遍(不得不赞Vue的文档,当年从Angular转Vue的时候看文档简直,舒服了~~)

本文主要内容:

  • 来源于Vue文档
  • 你可能看过
  • 但是你可能没用过

vue的数据响应失效了

你知道什么情况下,vue的数据响应会是失效吗? 官方举了个例子:

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的

在日常的业务的处理中,尤其是数组的for循环渲染,当你使用完v-for之后,动态的通过操作index指定数组的值,不是响应的。 我们使用实际业务代码举个例子:

<template>
  <div>
    <div v-for="(item,key) in list" :key="key">
      {{item}}
    </div>
    <button @click="changeList">失效</button>
    <button @click="respondList">响应</button>
    {{list}}
  </div>
</template>

<script>
export default {
  name: 'ex',
  data () {
    return {
      list: [11, 12, { money: 17 }]
    }
  },
  methods: {
    changeList () {
      // 失效代码
      this.list[0] = 16
      this.list.length = 0
    },
    respondList () {
      // 生效代码
      this.list[2].money = 0
      this.list[0] = 16
    }
  }
}
</script>

然后我们来看一下会发生什么

在这里插入图片描述
这就很有意思了,我们可以看到这个过程中,执行changeList()方法,页面上的11并没有变成16且数组也没有变为空数组,但是执行第二个方法时,this.list已经为空数组,导致报错。也就验证了官网所说没错,我们不可以直接操作数组的item值,你想要的响应并不会发生。

但是!大家可能会发现,好像自己项目里经常有这种操作,但是没有发生这种问题,那么我们来看一下是什么导致我们在项目中忽略了这个问题。 请看:

在这里插入图片描述
我直接执行了respondList (),但是可以看到this.list[0] = 16这句也跟着一起响应了,这就是为什么我们日常项目中没有出现这个问题的原因。

因为在日常项目中很少会有单独写一个方法去改list[index],通常会伴随着其他的对数组或者数组中对象的一些操作,而这些操作会触发Vue的响应,Vue响应不是响应我们的代码过程,他响应的是结果,而我们的代码过程只是意味着是否会触发Vue对代码结果的响应。

  • 简单说,执行第一个方法,里面的2行代码将list变为了空数组,但是这2行代码都不会触发Vue去响应,顾,页面不变。
  • 执行第二个方法,this.list[2].money = 0除了将money变为了0还触发了Vue的响应机制,也就是方法执行完之后Vue会对list进行更新,所以第2行this.list[0] = 16将整个list修改完之后,方法结束,Vue更新list

所以我们要规避在Vue直接去单独对数组的[index]和length去赋值,注意!是单独

vue的数据响应又又失效了?

你没看错,vue的数据响应又要上演失效了,这次的失效可能你平常项目中写过很多,但是 你还是没注意过! 该知识点来源于vue文档的列表渲染里面的一小段提示代码:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的

阔怕,你从来没想过你在项目中obj.a=1会不生效,这其中文档中有2句话很重要:

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除。 对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。

相信我的加粗已经让你意识到了问题所在,至于日常中为什么没有感觉到失效是和上个例子一样的,当然官方为这种单独操作对象属性方法

Vue.set(object, key, value)

具体使用方法可以回看文档。

不止在{{}}中可以使用函数

我要表达的意思是不止在双括号中可以使用函数,v-for也可以。 当然如果有人不知道双括号可以使用函数,我们先来演示一遍:

<template>
  <div>
    <div v-for="(item,key) in list" :key="key">
      {{filterList(item)}}
    </div>
  </div>
</template>

<script>
export default {
  name: 'ex',
  data () {
    return {
      list: [0, 1, 2]
    }
  },
  methods: {
    filterList (item) {
      if (item > 0) {
        return '大于0'
      } else {
        return item
      }
    }
  }
}
</script>

在这里插入图片描述
好的,接下来,文档告诉我们一个技巧,直接看官网示例:

<li v-for="n in evenNumbers">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

可以直接用一个函数来代替v-for中的list,这样可以结合计算属性避免我们在每次获取数据等业务场景下重新单独处理list。

函数中直接调用当前元素的原生事件

首先说一下这个技巧适用于:

  1. 你要为某个元素绑定一个事件
  2. 你的事件里可能需要操作业务的同时,根据业务操作浏览器原生事件

绑定事件时可以用特殊变量 $event 把它传入方法:

<button v-on:click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>
// ...
methods: {
  warn: function (message, event) {
    // 现在我们可以访问原生事件对象
    if (event) event.preventDefault()
    alert(message)
  }
}

该技巧适应场景有限,但是至少你要记住,vue可以直接在实践中绑定event,去操作原生事件,因为总有一天你会发现有些p需求需要你去实现……

Vue的修饰符很多你知道吗

有v-once也有.once

大家知道vue推荐对低开销的静态内容使用v-once渲染,但是如果你仔细看过文档你应该知道v-once,首先v-once的原理其实是keep-alive,它会缓存v-once的组件,但是希望你再阅读一次官方这句提示:

再说一次,试着不要过度使用这个模式。当你需要渲染大量静态内容时,极少数的情况下它会给你带来便利,除非你非常留意渲染变慢了,不然它完全是没有必要的——再加上它在后期会带来很多困惑。例如,设想另一个开发者并不熟悉v-once 或漏看了它在模板中,他们可能会花很多个小时去找出模板为什么无法正确更新

是的,除非你这个组件渲染的开销已经严重到你觉得他明显的慢,否则不要使用。

然后我们来说事件的.once

<!-- 点击事件只会执行一次 -->
<form @click.once="submit"></form>

要注意不能将其应用于按钮的点击之后,它不同于按钮的loading,点击按钮打开loading如果执行错误可以关闭loading,按钮可以再次执行。

而使用.once事件触发过一次之后,不会再次执行,当然你可以将它应用于其他事件,但是你要记住存在一个可以只让你的事件只触发一次的修饰符,总会用到的。

你认为的type="number"

大家在表单中如果要是用数字类型的input的时候通常我们会使用type=number,但是也许没有人注意到input真正返回是什么,比如:

<template>
  <div>
    {{age}}
    <input v-model.number="age" type="number" @change="lookAge">
    {{year}}
    <input v-model="year" type="number" @change="lookYear">
  </div>
</template>

<script>
export default {
  data () {
    return {
      age: null,
      year: null
    }
  },
  methods: {
    lookAge () {
      console.log(this.age)
    },
    lookYear () {
      console.log(this.year)
    }
  }
}
</script>

这一小段那代码有什么区别呢?

在这里插入图片描述
首先,在渲染上,至少结果都是正确的,console的结果也是没问题的,但是console调试的时候,蓝色数字和白色数字有什么区别,也许很多人都没注意过这个问题,回看看文档就可以让你理解我刚才提出的问题,文档原文:

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

<input v-model.number="age" type="number">

这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。 是滴,我觉得这对于用ts的人极其和谐。

如果你看到了上面的.number修饰符,那你一定可以在文档中接着看到.trim修饰符:

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

<input v-model.trim="msg">

这个问题我之前还真是碰见过,可惜我使用的方法是用js的trim去单独处理了一遍,殊不知文档如此简单,我竟然不好好阅读!

最后一个小技巧了

首先讲一讲我的菜鸟路程,在使用prop的时候刚开始我都是这样写:

props: {
  title,
  author
}

后来我这样写:

props: {
  title: String,
  author: Object
}

再后来我这样写:

props: {
  title:{
      type: String,
      required: true
    },
  author:{
      type: Object,
      required: true
    }
}

然后我读文档发现还可以这样写:

props: {
  // 带有默认值的对象
  title:{
      type: String,
       // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
  // 自定义验证函数
  author:{
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['au', 'th', 'or'].indexOf(value) !== -1
      }
    }
}

是的,prop也带有验证功能,且可以使用自定义验证函数! 发现这算是个小技巧,但是最重要的在这段文档后面:

当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或validator 函数中是不可用的。

最关键一句在验证函数中:data和计算属性中的变量和方法都不可用。

到这就结束了,这是我最近利用上下班时间我vue文档过了一遍,愿意主动将里面的一些遗漏或平常项目中很少用到,一直与忘记的小内容分享给各位。

如果有用给个评论,如果没用不要吐槽我好不好,求你们了,哈哈。

第一次分享,排版一般,还是希望有反馈的,如果有反馈,下次分享一篇基于某开源框架源码下的vuex实用代码分析