vue文档修订

250 阅读13分钟

Vue中文文档,重点摘录

  • 虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。

  • 所有的 Vue 组件都是 Vue 实例,并且接受相同的选项对象 (一些根实例特有的选项除外)。

  • 一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。 值得注意的是: 只有当实例被创建时就已经存在于 data 中的 property 才是响应式的。

  • 模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 。你不应该在模板表达式中试图访问用户定义的全局变量。 全局变量的一个白名单包括: 'Infinity,undefined,NaN,isFinite,isNaN,' 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' 'require'

  • 修饰符 修饰符 (modifier) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。 例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():

  • CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case)

  • 所有的.vue文件由三部分组成template,script,style,分别包含了组件的模板、脚本、样式.

  • Vue组件中的data必须是函数 Object是引用数据类型,每个组件的data都是同一个内存地址,一个数据改变了其他数据也改变了; 当我们的data是一个函数时,每一个实例的data属性都是独立的,不会相互影响了。

  • 在给子组件传递数据的时候,最好先在data中声明属性,然后传递属性,防止使用修饰符时出现无效和其他bug.

Vue的创建

一个简单的 Vue 实例只需要四步即可 创建vue实例

image.png


数据与方法

改变data属性,视图刷新的条件 image.png

声明周期函数示意图

声明周期函数示意图

image.png


Vue.nextTick()作用

语法: this.$nextTick( [callback] )
作用: 将回调延迟到下次 DOM 更新循环之后执行callback函数。

new Vue({
  // ...
  methods: {
    // ...
    example: function () {
      // 修改数据
      this.message = 'changed'
      // DOM 还没有更新
      this.$nextTick(function () {
        // DOM 现在更新了
        // `this` 绑定到当前实例
        this.doSomethingElse()
      })
    }
  }
})

Vue.nextTick 异步更新队列

模板语法-插值表达式

  • 正确用法
{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}
  • 错误用法
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
// 赋值语句,也不是表达式(假如a是data中的属性)
{{ a=2 }}

<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}

计算属性缓存 vs 方法

  • 对于任何复杂逻辑,都应当使用计算属性;
  • 因为计算属性有缓存机制,重复调用会返回缓存.
  • 方法每次都会执行函数体中的操作,增加性能损耗. 我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。如果使用方法,会多次执行函数增加性能损耗.
//注意: 
//计算属性now将不再更新,因为 Date.now() 不是响应式依赖:
computed: {
  now: function () {
    return Date.now(); //非响应式依赖,不会缓存
  },
  reversedMessage: function () {
    return this.message.split('').reverse().join(''); //响应式依赖,会缓存
  }
}

计算属性 vs 侦听属性

侦听器watch的用法

  • 当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch.
  • 通常更好的做法是使用计算属性而不是命令式的 watch 回调。 Demo演示
<div id="demo">{{ fullName }}</div>
//监听属性
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})
//计算属性
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

  • 侦听器的优点 计算属性和侦听器都可以响应数据的变化, 但当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

计算属性的setter

  • 计算属性默认只有 getter,不过在需要时你也可以提供一个 setter: Demo
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

Class与Style绑定

  • class与style绑定的类型可以是: 字符串、对象、数组
  • 字符串时,可以传递表达式,根据条件显示对应的样式
  • 对象时,可以传递data中的property, 也可以传递methods中的方法,还可以传递computed中的计算属性.
  • 数组时, 可以传递多个对象(万物皆对象) 子组件样式优先级大于父组件

image.png


v-if、v-show、v-for

使用v-if、v-else、v-else-if的时候, 可以用key来管理可复用的元素
注意,v-show 不支持 <template> 元素,也不支持 v-else。
v-if是真正的渲染, 它会确保在切换条件过程中,块内的元素的事件监听器和子组件适时的销毁和重建; v-show只是简单的切换css.
v-if的切换开销大, v-show则是初始渲染开销大,频繁切换使用v-show, 运行时经常改变则使用v-if.
v-if和v-for一起使用时, v-for的优先级更高, 会导致无论v-if是否为ture,都会遍历整个循环. 

v-for遍历时,可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>

在 v-for 里使用值范围
<div>
  <span v-for="n in 10">{{ n }} </span>
</div>
//结果: 1 2 3 4 5 6 7 8 9 10 

v-for和<template>搭配可减少渲染次数
v-for和自定义组件使用时,需要使用props来传递值
在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下都一致。

不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。
2.2.0+ 的版本里,当在组件上使用 v-for 时,key 现在是必须的。

v-for可遍历数组,第一个参数是obj,第二个参数是索引(index)
v-for可遍历对象,第一个参数是value,第二个参数是key,第三个参数是索引.
遍历对象,一个参数时,会输出对象中的value 
sexDict: {boy: '男',}
<div v-for="sex in sexDict" :key="sex">
   {{sex}}  //结果为"男"
</div>



尽可能为遍历元素加上key,获得渲染优化.(Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。)
//label会高度复用,input因为设置了不同的key所以不会被复用,每次切换loginType的时候,块内元素都会被重新销毁和创建.
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

在 <template> 元素上使用 v-if 条件渲染分组, 最终的渲染结果将不包含 <template> 元素。
v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>



数组

  • Demo参考组件 component/array.vue
  • 数组变异方法: push/pop/unshift/shift/splice/sort/reverse改变原始数组

  • 数组非变异方法: filter/concat/slice不改变原始数组,总是返回新数组

  • 深入响应式原理检测变化:

对于对象来说:

1, Vue只能检测初始化时data中对象的属性,初始化之后如果给对象添加或移除属性,Vue无法检测到对象变化,从而视图不会更新.
2, 对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。
但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。
Vue.set(people,'name','王五');
或
this.$set(people,'name','王五');
3, 有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。
但是,这样添加到对象上的新 property 不会触发更新。
在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

对于数组来说:

Vue 不能检测以下数组的变动:

当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength

解决方案:
// Vue.set(方式1)
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice(方式2)
vm.items.splice(indexOfItem, 1, newValue)

    //以下方法会改变原数组
    push() //接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度.
    unshift() //在数组开头添加任意多个值,然后返回新的数组长度
    shift() //用于删除数组的第一项,同时减少数组的length值,返回被删除的项
    pop() //用于删除数组的最后一项,同时减少数组的length值,返回被删除的项
    splice() //传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组.
    sort(); //数组里的项从小到大排序(默认转换为字符串比较,如果需要按照数字大小排序,需要自己实现函数), 改变数组
    reverse(); //用于颠倒数组中元素的顺序, 改变原数组

    //以下方法都不影响原数组
    slice(); //传入两个参数,分别是开始位置,要截取的长度,返回截取的新数组,不改变原数组
    indexOf();  //要查找的元素在数组中的位置,如果没有则返回-1
    includes(); //数组中是否包含某个元素
    find(); //过滤  //返回数组中满足条件的第一个元素的值,如果没有,返回undefined
    findIndex(); //返回数组中满足条件的第一个元素的索引(下标), 如果没有找到,返回-1
    foreach(); //作用类似for循环, 数组中的每个元素执行一次提供的(回调)函数。这个方法没有返回值。不影响原数组
    filter(); //遍历数组中所有的元素,返回值为符合条件的新数组,不改变原数组.(注意:不会对空数组进行检测)
    map(); //遍历数组中每个元素,自定义处理后,返回值为每个处理后的元素组成的新数组, 如果某个元素没有return,则为null.不改变原数组(注意:不会对空数组进行检测)
    some(); //数组中有至少一个元素满足就会返回true;所有元素都不满足返回值才会为false。
    every(); //数组所有元素是否都符合指定条件,如果有一个元素不满足,则返回false
    join(); //数组转字符串, 会改变原数组  //join(a),可以指定参数a,当做数组中元素的连接符

事件处理

  • 传递方法名称
<div id="example-2">
  <!-- `greet` 是在下面定义的方法名 -->
  <button v-on:click="greet">Greet</button>
</div>
  • 除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:
<div id="example-3">
  <button v-on:click="say('hi')">Say hi</button>
  <button v-on:click="say('what')">Say what</button>
</div>
  • 有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $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)
  }
}

事件修饰符

Demo

image.png


在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.stop
.prevent
.capture
.self
.once
.passive

// 阻止单击事件继续传播 
<a v-on:click.stop="doThis"></a>

// 提交事件不再重载页面 (指定submit时,点击按钮会重新加载页面,.prevent可以阻止页面重载)
<form v-on:submit.prevent="onSubmit"></form>

// 修饰符可以串联 
<a v-on:click.stop.prevent="doThat"></a>

// 只有修饰符 
<form v-on:submit.prevent></form>

// 添加事件监听器时使用事件捕获模式 
// 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 
<div v-on:click.capture="doThis">...</div>

// 只当在 event.target 是当前元素自身时触发处理函数 
// 即事件不是从内部元素触发的 
<div v-on:click.self="doThat">...</div>

//2.1.4 新增
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

2.3.0 新增
Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符。
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
这个 .passive 修饰符尤其能够提升移动端的性能。

表单输入绑定

multiple的意思是,单选框展示一个变为展示多个选项,多选的方式为安装shift进行多选,展示多个

  • 用 v-model 指令在表单 input、textarea 及 select 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

  • 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

  • 对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
text 和 textarea 元素使用 value property 和 input 事件;
checkbox 和 radio 使用 checked property 和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。

修饰符

.native

作用:在一个组件的根元素上直接监听一个原生事件 native表示原生事件,用于自定义组件, 将事件绑定到自定义组件的html标签上,dom.addEventListener('click', handler)

.lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,
从而转为在 change 事件_之后_进行同步:
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">

.number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:
<input v-model.number="age" type="number">
这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

.trim

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

.sync

.sync修饰符Demo

// 只需要在父组件绑定属性x上添加 .sync,在子组件内部就可以触发 update:属性名 来更新属性x
<child-sync :work.sync="student"></child-sync>

组件注册

组件名

(推荐:字母全小写且必须包含一个连字符)

全局注册

在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中.

Vue.component('my-component-name', { /* ... */ });
当直接在 DOM 中使用一个组件 (而不是在字符串模板或单文件组件) 的时候,我们强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)。这会帮助你避免和当前以及未来的 HTML 元素相冲突。

组件名大小写,

定义组件名的方式有两种:


➤ 使用 kebab-case
Vue.component('my-component-name', { /* ... */ })
当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 <my-component-name>。

➤ 使用 PascalCase
Vue.component('MyComponentName', { /* ... */ })
当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 <my-component-name> 和 <MyComponentName> 都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。

局部注册

在用到的文件中单独引入.

你可以通过一个普通的 JavaScript 对象来定义组件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components 选项中定义你想要使用的组件:
new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})
或者如果你通过 Babel 和 webpack 使用 ES2015 模块,那么代码看起来更像:
import ComponentA from './ComponentA.vue'

export default {
  components: {
    ComponentA
  },
  // ...
}
注意在 ES2015+ 中,在对象中放一个类似 ComponentA 的变量名其实是 ComponentA: ComponentA 的缩写,
即这个变量名同时是:
用在模板中的自定义元素的名称
包含了这个组件选项的变量名

基础组件&自动化全局注册

可能你的许多组件只是包裹了一个输入框或按钮之类的元素,是相对通用的。我们有时候会把它们称为基础组件,它们会在各个组件中被频繁的用到 如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false. 注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。 Demo

Vue.component('my-component', {
  inheritAttrs: false,
  // ...
})

Prop

prop传参&事件 ABC三代传参&触发事件

  • 这意味着,不应该在一个子组件中改变prop, 如果改变了, 浏览器会在控制台中发出警告.
  • 一个非prop的attribute传给了子组件,这些attribute会被添加到这个组件的根元素上.

Prop 的大小写 (camelCase vs kebab-case)

HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>
重申一次,如果你使用字符串模板,那么这个限制就不存在了。

传入一个数字时

即便 '42' 是静态的,我们仍然需要 'v-bind' 来告诉 Vue

<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:likes="42"></blog-post>

<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:likes="post.likes"></blog-post>

传入一个布尔值

<!-- 包含该 prop 没有值的情况在内,都意味着 `true`。-->
<blog-post is-published></blog-post>

<!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:is-published="false"></blog-post>

<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:is-published="post.isPublished"></blog-post>

传入一个数组

<!-- 即便数组是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>

<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>

传入一个对象

<!-- 即便对象是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post
  v-bind:author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
></blog-post>

<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:author="post.author"></blog-post>

传入一个对象的所有 property

如果你想要将一个对象的所有 property 都作为 prop 传入,
你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。
例如,对于一个给定的对象 post:
post: {
  id: 1,
  title: 'My Journey with Vue'
}
下面的模板:
<blog-post v-bind="post"></blog-post>
等价于:
<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

子组件中想要改变prop,又不影响prop

注意: 在js中对象和数组是通过引用传入的(引用类型), 在子组件中改变这个对象或数组将会影响父组件的状态.

这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 用作其初始值:
props: ['initialCounter'],
data: function () {
  return {
    counter: this.initialCounter
  }
}
这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

prop验证

Demo1

  // 父组件给子组件传递任意类型数据
  props: ['title','age','p'],

  // 子组件限制父组件传递的数据类型
  props: {
    title: String,
    age: {
      type:[Number,String],
      default:'99',
      required:true
    },
    p: {
      type: Object,
    },
  },

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

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

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

类型检查

type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认是否是一个类的实例 type 可以是下列原生构造函数中的一个: tip 重点摘要: String Number Boolean Array Object Date Function Symbol

自定义事件

事件名

(推荐始终使用 kebab-case(短横线分隔) 的事件名。) 不同于组件和 prop,事件名不存在任何自动化的大小写转换。

// 如果使用 v-on:myEvent 将会自动转换为全小写 v-on:myevent 
// 因为HTML是大小写不敏感的
<my-component v-on:my-event="doSomething"></my-component>
this.$emit('myEvent'); //只能监听到v-on:my-event

String 字符串用法

indexOf()

字符串中是否包含searchValue, 第二个参数可以忽略,表示从第几位开始检查.

  • str.indexOf(searchValue , fromIndex)

    var str = 'bcdefabalkj';
    console.log('返回结果:' + str.indexOf('a'));  //返回值为第一次检索到该字符的位置为5
    console.log('返回结果:' + str.indexOf('a',20));  //返回值为-1, 表示没有找到该字符
    // 当被搜索的值为''或undefined时,返回值:
    console.log('返回结果:' + str.indexOf('',11));  //0<fromIndex<=11时,返回值为fromIndex; fromIndex>11时,返回值都为11
    console.log('返回结果:' + str.indexOf('',20));  //返回值为11, 表示str的长度
    console.log('返回结果:' + str.indexOf(undefined,20));  //返回值为-1, 表示没有找到该字符
  • 获取链接中最后一个&的参数
var str = "http://www.baidu.com?url=http://www.ncexc.com?token=token1&index=i&type=pdf";

var index = str.lastIndexOf("&");
str = str.substring(index + 1, str.length);
console.log(str); //type=pdf

split()

方法使用指定的分隔符字符串将一个String对象分割成子字符串数组

const str = 'The quick brown fox jumps over the lazy dog.';

const words = str.split(' ');
console.log(words[3]);
// expected output: "fox"

字符串中替换字符

str.replace(regexp|substr, newSubStr|function)

    /* 
      使用正则表达式匹配字符串,可以替换所有的匹配结果.

      在 replace() 中使用 global 和 ignore 选项
      global:全局替换(g)
      ignore:忽略大小写(i)
    */
    var re = /apples/gi;
    var str = "Apples are round, and apples are juicy. I like apples.";
    var newstr = str.replace(re, "oranges");
    console.log(newstr);  //输出结果: oranges are round, and oranges are juicy. I like oranges.

    /* 使用字符串替换字符串,只会替换第一个匹配结果,且区分大小写 */
    var newstr2 = str.replace('apples', "oranges");
    console.log(newstr2); //输出结果: Apples are round, and oranges are juicy. I like apples.

使用replace()交换两个单词的位置

    var re = /(\w+)-(\w+)/;  //表示匹配:  字母组合-字母组合
    var str = "John-Smith";
    /* 
      "$2, $1"是一个整体,作为第二个参数;
      第一个参数re会被第二个参数替换掉;
      第二个参数中$1表示a, $2表示b (原理可以理解: 字符串"a-b"会以特殊字符'-'拆分为2个参数$1,$2)
    */
    var newstr = str.replace(re, "$2, $1");  //第二个参数可以任意指定格式
    console.log(newstr); // Smith, John

全局自动注册自定义组件

(必须使用webpack的项目,vue-cli项目可以) vuepress会自动注册components目录下所有的vue文件 全局自动注册自定义组件

image.png

//(globalComponents.js)
import Vue from 'vue'
function changeStr (str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

//获取当前js同级的所有xxx.vue文件
const requireComponent = require.context('./', false, /\.vue$/)
// 查找同级目录下以vue结尾的组件
const install = () => {
  //输出: "./HelloWorld.vue", "./VFor.vue", "./VTags.vue", "./Vhr.vue"
  console.log(requireComponent.keys()); 
  requireComponent.keys().forEach(fileName => {
    let config = requireComponent(fileName)
    console.log(config) 
    // 比如: ./VTags.vue 用正则替换./和.vue,拿到VTags
    let componentName = changeStr(
      fileName.replace(/^\.\//, '').replace(/\.\w+$/, '')
    )
    Vue.component(componentName, config.default || config)
  })
}
export default {
  install // 对外暴露install方法
}

全局手动注册自定义组件

方式1: 在main.js中直接注册组件 image.png


方式2(推荐): 创建独立的js文件并注册组件,然后在main.js中全局引用组件

image.png


.prevent和.passive区别

tip 重点摘要:

  • prevent 是拦截默认事件,passive是不拦截默认事件。
  • passive和prevent冲突,不能同时绑定在一个监听器上。 参考地址>

详解

  • prevent: 某些标签拥有自身的默认事件,如a[href="#"],button[type="submit"] 这种标签在冒泡结束后会开始执行默认事件。注意默认事件虽然是冒泡后开始,但不会因为stop阻止事件传递而停止。


  • passive: 明明默认执行为什么会设置这样一个修饰符? 【浏览器只有等内核线程执行到事件监听器对应的JavaScript代码时,才能知道内部是否会调用preventDefault函数来阻止事件的默认行为,所以浏览器本身是没有办法对这种场景进行优化的。这种场景下,用户的手势事件无法快速产生,会导致页面无法快速执行滑动逻辑,从而让用户感觉到页面卡顿。】

通俗点说就是每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。我们加上passive就是为了告诉浏览器,不用查询了,我们没用preventDefault阻止默认动作。

这里一般用在滚动监听,@scoll,@touchmove 。因为滚动监听过程中,移动每个像素都会产生一次事件,每次都使用内核线程查询prevent会使滑动卡顿。我们通过passive将内核线程查询跳过,可以大大提升滑动的流畅度。

路由跳转

//A-B-C 从C-B返回时,B还能获取到query参数
this.$router.push({
    path: "longcontract",
    query: {
        id: code
    }
});
//下一页获取参数
this.$route.query.id;
//A-B-C 从C-B返回时,B不能获取到params参数
this.$router.push({
    name: "longcontract",
    params: {
        id: code
    }
});
this.$route.params.id;

Object.assign()

语法: Object.assign(target, ...sources)
参数:
target: 目标对象。
sources:  源对象。
返回值: 目标对象。
如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
console.log(target); //{ a: 1, b: 2 }

const returnedTarget = Object.assign(target, source);

console.log(target); //改变了目标对象
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }

配置环境变量env

  • 原理
采用`node.js`顶层对象中的`process.env`(进程环境,返回一个包含用户环境信息的对象)属性,
根据各个环境的配置文件区分和切换环境
只有以 `VUE_APP_` 开头的变量会被 `webpack.DefinePlugin` 静态嵌入到客户端的包中。
你可以在应用的代码中这样访问它们:
console.log(process.env.VUE_APP_SECRET)

`VUE_APP_*` 变量之外,在你的应用代码中始终可用的还有两个特殊的变量:
`NODE_ENV` - 会是 `"development"``"production"` 或 `"test"` 中的一个。
`BASE_URL` - 会和 `vue.config.js` 中的 `publicPath` 选项相符,即你的应用会部署到的基础路径。

提示:
你可以在 `vue.config.js` 文件中计算环境变量。它们仍然需要以 `VUE_APP_` 前缀开头。
process.env.VUE_APP_VERSION = require('./package.json').version
//在module.exports上面↑加
module.exports = {
  // config
}
  • 应用
1, 在项目根目录创建`.env.dev` 和`.env.prod`两个文件, 并填充环境变量信息
2, 在package.json中增加快捷指令
(如果不添加指令,会报TypeError: Cannot read property 'upgrade' of undefined)
3, 其他位置访问环境变量信息
console.log(process.env.NODE_ENV);
console.log(process.env.VUE_APP_TITLE);
console.log(process.env.VUE_APP_BASE_URL);

image.png

image.png