Vue.js学习笔记(五)

Posted by Ivens on November 27, 2019

前言

在这几天学习的过程中发现一个问题,有的时候老师在视频中出现Vue warn的地方我都没有,而且可以正常显示.

一开始我以为是版本的问题,可能我现在用的是最新版Vue,一些问题都已经解决了.但是直到今天(2019年11月27日)我才发现原因.

BootCDN中引用Vue时,我选择了min版本的,这造成很多warn不会被报出来.

以后开发的时候还是使用common版或者未压缩的更好.

ES6多行字符串与连接字符串的表示方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 旧版写法
alert("你好,\n 我叫\n Olive");


// 新版写法
alert(`你好
我叫
olive`);//注意这里的两个点是键盘上数字键1左边的按键,而不是单引号哦

// 以前,把多个字符串连接起来,可以用+号连接
var name ="olive";
var age= 26;
var message='hello,my name is '+name+',I\'m '+age+' years old';
alert(message);


// 但要是有很多变量需要连接,用+号就比较麻烦了。ES6新增了一种字符串连接方式:
var name1 ="Mike";
var age1=20;
var message1=`hello,${name1},your age is ${age1}`;//同理,这里的两个点是键盘上数字键1左边的按键,而不是单引号哦
alert(message1);

正文

组件中使用的细节点

使用is解决H5的小bug

《Vue官方文档—is》

先看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="root">
  <table>
    <tbody>
      <row></row>
      <row></row>
      <row></row>
    </tbody>
  </table>
</div>
<script>
  Vue.component('row',{
    template: '<tr><td>XXX</td></tr>'
  })
  var vm = new Vue({
    el: '#root'
  })
</script>

当我们这样使用组件时会出现以下问题: 这时,row组件中添加的tr全部都在table外面,原因是在H5的规范中,要求我们在tbody中只能放tr标签,当浏览器解析到的是row标签时,就会出现这样的问题.

解决这个问题可以使用Vue提供的is属性.

1
2
3
4
5
6
7
8
9
<div id="root">
  <table>
    <tbody>
      <tr is="row"></tr>
      <tr is="row"></tr>
      <tr is="row"></tr>
    </tbody>
  </table>
</div>

组件中的data必须以函数形式定义

组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝.

如果 Vue 没有这条规则,改变一个组件中的data会影响到其它所有实例.

ref的使用

《Vue官方文档—ref》

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。

如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例.

父子组件的数据传递

单向数据流

《官方文档—单向数据流》

父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop

如果你这样做了,Vue 会在浏览器的控制台中发出警告。

解决方法:

在子组件中加入data,在其中定义一个空值接收父组件传入的值.后面对这个新定义的值进行改动即可.

vm.$emit的使用

《父子组件间通信实例讲解(props、$ref、$emit)》

1
vm.$emit( event, arg )

$emit 绑定一个自定义事件event,当这个这个语句被执行到的时候,就会将参数arg传递给父组件,父组件通过@event监听并接收参数。

组件参数校验

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
var counter = {
  // props: ['content'],     这是最普通的使用方法

  props: {

    // content: String      这种写法可以规定传入值的类型

    content: {

      // 检测类型,可以像上面一样只符合一种类型,也可以用数组包括很多种类型
      type: [String,Number],

      // 规定是否必须传入一个对应的参数
      required: false,

      // 规定如果没传入对应值,则使用该默认值
      default: 'default value',

      // 校验器(validator)  value为传入的值,通过判断返回值来判断是否报出警告
      validator: function(value){
        return (value.length > 5)
      }
    }

  },
  template: '<div>{{content}}</div>'
}

非props特性与为组件绑定原生事件

非props特性

  1. 无法在子组件中调用
  2. 该属性会显示在DOM中

为组件绑定原生事件

在事件后加.native即可,如:

1
<child @clcik.native="handleClick()"></child>

非父子组件间传值(Bus/总线/发布订阅模式/观察者模式)

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
34
35
36
37
38
<body>
  <div id="root">
    <child content="I am A"></child>
    <child content="I am B"></child>
  </div>
  <script>
    Vue.prototype.bus = new Vue();

    Vue.component('child',{
      props:{
        content: String
      },
      data: function() {
        return {
          selfContent : this.content
        }
      },
      methods: {
        handleClick () {
          this.bus.$emit('change', this.selfContent);
        }
      },
      mounted() {
        var this_ = this;
        this.bus.$on('change',function (msg) {  
          // 注意:这里的alert函数会触发两次,因为两个父组件都被触发了change事件
          // alert(msg);
          this_.selfContent = msg
        });
      },
      template: '<div @click="handleClick()">{{selfContent}}</div>'
    })

    var vm = new Vue({
      el: '#root'
    })
  </script>
</body>

先为Vue的原型添加一个bus的方法,然后当我们点击div时,会向bus提交一个当前content的参数,因为其他父组件也会被触发事件,所以数值一起发生改变.

插槽

父组件向子组件传递DOM结构时使用.

使用方法,在子组件中添加slot标签:

1
template: '<div><slot></slot></div>'

具名插槽

如果要选择性提取父组件元素,则在HTML元素中给对应的标签添加slot属性:

1
<div class="header" slot="header">header</div>

再在子组件中使用name属性调用:

1
template: '<div><slot name="header"></slot></div>'

作用域插槽

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
<body>
  <div id="root">
    <child>
      <template slot-scope="listData">
        <li> </li>
      </template>
    </child>
  </div>
  <script>
    Vue.component('child',{
      data() {
        return {
          list: [1,2,3,4]
        }
      },
      template: `<div>
                  <ul>
                    <slot v-for="item of list" :item=item></slot>
                  </ul>
                </div>`
    })
    var vm = new Vue({
      el: '#root'
    })
  </script>
</body>

这里相当于把<li>标签作为slot传入子组件中,子组件再向其传递参数item完成显示.在父组件中使用template是模板格式.

为什么要是用作用域插槽?

有时候一个子组件被多个父组件调用,每个父组件想呈现的样式不同,如果在子组件中设定死了代码复用性下降.

v-slot语法

v-slot 指令自 Vue 2.6.0 起被引入,提供更好的支持 slotslot-scope 特性的 API 替代方案。在接下来所有的 2.x 版本中 slotslot-scope 特性仍会被支持,但已经被官方废弃且不会出现在 Vue 3 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 原slot语法
<div slot="header"></div>

// 使用v-slot语法,或使用简写'#'
<div v-slot:header></div>
<div #header></div>

// 原 slot-scope 语法
<template slot-scope="listData">
  <li> </li>
</template>

// 使用 v-slot 语法
<template v-slot="listData">
  <li> </li>
</template>

或者可以将具名插槽和作用域插槽结合起来,如:

1
2
3
<template v-slot:footer="listData">
  <li> </li>
</template>

一句话概括就是v-slot :后边是插槽名称,=后边是组件内部绑定作用域值的映射。

动态组件与v-once指令

动态组件

1
<component :is="type"></component>

通过is判断调用哪个组件,is传入子组件名.

v-once指令

只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。当元素不随数据的变化而变化,可以加上这个.

1
2
<!-- 单个元素 -->
<span v-once>This will never change: </span>