Vue.js官方文档温故小结

来阅读和总结一下Vue官方文档吧~(平时自己不太清晰或者没有注意到的部分内容)

箭头函数里的this拿不到Vue实例对象: 因为箭头函数是和父级上下文绑定在一起的

所以不要出现以下错误的写法:

1
2
created: () => console.log(this.a)
vm.$watch('a', newValue => this.myMethod())

v-once:指令只执行一次插值,数据变化时不更新。

v-html:不要对用户提供的内容使用插值,容易导致XSS攻击

场景: 一个提交评论的功能,评论内容是v-html来展示的,用户提交一个可执行的script脚本用来窃取cookie,token,用户信息等等。其它用户查看该评论时v-html自动执行脚本,信息被窃取。

动态style:对象语法{}一个对象,动态切换class;数组语法[],多个class。vue.js会自动添加需要添加浏览器引擎前缀。

自定义组件上的class: 会添加到该组件根元素而不是覆盖。

动态style:

对象语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
// html
<div v-bind:style="styleObject"></div>
<div :style="{color: activeColor}">
// js
data() {
return{
styleObject: {
color: 'red',
fontSize: '13px'
},
activeColor: 'green'
}
}

数组语法:

1
<div v-bind:style="[baseStyles, overridingStyles]"></div>

浏览器前缀2.3.0+版本属性值可以是一个带前缀的数组,之后渲染最后一个值

1
<div :style="{display: ['-webkit-box', '-ms-flexbox', 'flex']}"></div>

v-if和template元素:

何时使用template:

  • 当条件判断需要切换不同的元素时使用。template标签天生不可见,当需要对一些内容进行v-if条件判断时,可以在外层包裹template元素,减少dom层。
  • 只是显示或隐藏同一个元素,直接在元素上v-if即可,或者外层包裹div

  • v-else

  • v-else-if

需要紧跟在v-if后面,否则不识别。与条件判断语句逻辑相同

key管理元素复用:Vue默认复用已有元素,不会从头开始渲染,效率比较快。

  • 给元素加上key属性:表示完全独立的元素,不复用。

终于知道为什么v-for要绑定key了,防止复用,唯一

  • v-show与v-if: 如果在允许时条件很少改变使用v-if较好,频繁的变化使用v-show较好。

    • v-show: 只是改变display属性是否为none,一开始就会被渲染,每次都会被渲染;
    • v-if: 只有当条件为真时才渲染,影响dom,销毁和重建
  • v-if 与 v-for一起使用时:v-for 优先级更高,v-if会重复运行于每个v-for循环中(类似于循环内部的if判断)

  • v-for: 记得动态绑定key

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <--数组-->
    <ul id="example-1">
    <li v-for="(item, index) in arr" :key="item.id">
    {{ item.message }}
    </li>
    </ul>

    <--对象-->
    <ul id="example-2">
    <li v-for="(value, key, index) in obj" :key="key">
    {{key}} - {{value}} -{{index}}
    </li>
    </ul>

数组

  • 会改变原数组的方法
    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()
  • 不改变原数组的方法
    • filter()
    • concat()
    • slice()

避免不必要的处理数据出现的bug(最近我自己就用sort又忘记它会改变原数组)

  • 检测不到数组变化的情况

    • 利用索引直接设置一个项时arr[index] = newValue;

      解决:

      ​ this.$set(arr, index, newValue)

      ​ arr.splice(index, 1, newValue)

    • 修改数组长度 arr.length = newLength;

      解决:

      ​ arr.splice(newLength)

对象更改检测注意事项:检测不到对象属性的添加或删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div>{{obj}}</div>
data() {
return {
obj: {
name: 'holly'
}
}
}
// 给obj添加一个age属性
obj.age = 3 // 虽然添加了属性但是插值并没有变化
/**
*解决方法
*/
// 使用$set
this.$set(obj, 'age', 3)
// 使用Object.assign或者lodash的extend方法 用两个对象属创建新的对象
this.obj = Object.assign({}, this.obj, {age: 3})
  • v-fortemplate: 用于渲染多个元素的时候

    1
    2
    3
    4
    5
    6
    <ul>
    <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
    </template>
    </ul>

事件

  • 想要拿到event对象,传入特殊变量$event即可

  • v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。 (一直不太理解,下面这个图感觉解释的比较清楚)

    ![](Vue-js官方文档温故小结\QQ截图20180809174430.png %}

  • 事件修饰符.prevent :对应addEventListener 中的 passive 选项(解决移动端滑动,滚动卡顿而诞生的)

    • 这个 .passive 修饰符尤其能够提升移动端的性能。
    • 不要把 .passive.prevent 一起使用
  • 按键修饰符

    • ASCII码值

      1
      <input v-on:keyup.13="submit">
    • 按键别名

      • .enter
      • .tab
      • .delete
      • .esc
      • .space
      • .up
      • .down
      • .left
      • .right

    可以通过全局 config.keyCodes 对象自定义按键修饰符别名:

    1
    2
    // 可以使用 `v-on:keyup.f1`
    Vue.config.keyCodes.f1 = 112
  • 鼠标按钮修饰符2.2.0+

    • .left
    • .right
    • .middle

表单

v-model 指令在表单 input、textarea 及 select 元素上创建双向数据绑定

  • 修饰符
    • .lazy: 原本v-model绑定的值是实时更新的,这个修饰符就是转变为change事件同步,change事件是失去焦点时触发。
    • .number: 将输入的值转为数值。
    • .trim: 过滤首尾空白字符

组件

基础组件的自动化全局注册:多个全局共用的基础组件时使用(暂时没有用到过,点击跳转官网)
  • 组件上的事件修饰符.native: 可以监听组件根元素事件
  • .sync修饰符: props传递的值是单向数据流,想父组件传递给子组件,子组件更新这个值,父组件也同步更新。这时可以使用.sync实现prop”双向绑定”。

slot插槽

  • 匿名插槽: 父组件内容分发到插槽

  • 具名插槽: 子组件slot插槽的name属性和父组件slot属性对应,分发到对应name的插槽

  • 插槽默认内容:组建插槽内可以有默认内容,当父组件为这个插槽提供了内容,将被覆盖。

  • 作用域: 父组件模板的内容都会在父组件作用域内编译,子组件模板的所有内容都会在子组件作用域内编译。

  • 作用域插槽:可以从子组件获取数据的可复用插槽

    写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <!-- 组件 todo-list-->
    <ul>
    <li
    v-for="todo in todos"
    v-bind:key="todo.id"
    >
    <!-- 我们为每个 todo 准备了一个插槽,-->
    <!-- 将 `todo` 对象作为一个插槽的 prop 传入。-->
    <slot :todo="todo" :arr="arr">
    <!-- 回退的内容 -->
    {{ todo.text }}
    </slot>
    </li>
    </ul>
    <!-- 父组件使用组件 -->
    <todo-list v-bind:todos="todos">
    <!-- 将 `slotProps` 定义为插槽作用域的名字 -->
    <template slot-scope="slotProps">
    <!-- 为待办项自定义一个模板,-->
    <!-- 通过 `slotProps` 为一个对象 插槽可以传入多个prop-->
    <span v-if="slotProps.todo.isComplete"></span>
    {{ slotProps.todo.text }}
    <span> {{ slotProps.arr }} </span>
    </template>
    </todo-list>
    <!-- slot-scope 使用结构赋值的写法 看起来更简洁一些-->
    <todo-list v-bind:todos="todos">
    <template slot-scope="{todo, arr}">
    <span v-if="todo.isComplete"></span>
    {{ todo.text }}
    <span> {{ arr }} </span>
    </template>
    </todo-list>

动态组件:component 的is属性

1
2
<component v-bind:is="currentTabComponent"></component>
<button @click="handleChangeView">切换</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
components:{
comA:{
template:`<div>组件A</div>`
},
comB:{
template:`<div>组件B</div>`
},
comC:{
template:`<div>组件C</div>`
}
},
data:{
currentTabComponent:'comA'
},
methods: {
handleChangeView() {
this.currentTabComponent = 'comB'
}
}

结合keep-alive做缓存

1
2
3
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>

异步组件:需要的时候才从服务器加载这个模块。

  • 全局注册

    1
    2
    3
    4
    5
    Vue.component(
    'async-webpack-example',
    // 这个 `import` 函数会返回一个 `Promise` 对象。
    () => import('./my-async-component')
    )
  • 局部注册

    1
    2
    3
    components: {
    'my-component': () => import('./my-async-component')
    }
  • 2.3.0+新增异步组件函数返回对象属性:来处理加载状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const AsyncComponent = () => ({
    // 需要加载的组件 (应该是一个 `Promise` 对象)
    component: import('./MyComponent.vue'),
    // 异步组件加载时使用的组件
    loading: LoadingComponent,
    // 加载失败时使用的组件
    error: ErrorComponent,
    // 展示加载时组件的延时时间。默认值是 200 (毫秒)
    delay: 200,
    // 如果提供了超时时间且组件加载也超时了,
    // 则使用加载失败时使用的组件。默认值是:`Infinity`
    timeout: 3000
    })

特殊情况: 一些需要对vue规则做一些小调整的特殊情况

  • 访问根实例: $root (项目比较大时推荐vuex)

  • 子组件访问父组件实例: $parent

  • 访问子组件或子元素:给组件绑定ref,通过$ref访问,$refs在组件渲染完成之后生效,不是响应式

  • 依赖注入:父组件通过provide提供变量及方法,子组件通过inject注入(依然推荐vuex)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 父组件
    provide: function () {
    return {
    getMap: this.getMap,// 方法
    mapInfo: this.mapInfo // 对象数据
    }
    }
    // 子组件
    inject: ['getMap', 'mapInfo']

事件侦听器:

  • $on
  • $once
  • $off

循环引用

  • 递归组件: 组件可以在自己的模板中调用自身,确保递归是条件性的,避免无限循环

    1
    2
    3
    name: 'stack-overflow',
    template: '<div><stack-overflow></stack-overflow></div>'
    // 死循环,可以使用v-if条件判断

控制更新

  • 强制更新:极少数情况下需要手动强制更新可以通过$forceUpdate

  • v-once创建静态组件:需要渲染大量静态内容,除非觉得渲染非常慢,否则不推荐

    1
    2
    3
    4
    5
    6
    <div v-once> 
    <h1>
    大量静态数据
    </h1>
    ...
    </div>

过渡 & 动画 点击跳转

------ 本文结束------
0%