天天看点

VUE基础Vue基础

VUE基础

  • Vue基础
    • 数据绑定
    • 过滤器
    • 指令
    • 计算属性
      • 计算属性的getter、setter方法
      • 计算属性扩展
      • 计算属性缓存
    • v-bind
      • 绑定class
        • 使用对象语法绑定class:
        • 使用数组语法绑定class
      • 绑定内联样式
        • 使用数组语法绑定多个样式
    • 内置指令
      • v-cloak
      • v-pre
      • v-once
      • v-if、v-else-if、v-else
      • v-for
        • v-for迭代整数
        • 更新数组触发数据改变的方法
      • v-on
    • v-model
    • 组件
      • 挂载组件
      • 通过props传递数据:
      • 子组件向父组件传值
      • 使用v-model和$emit传值
    • 中央事件总线
      • 父(\$parent)链传递数据
      • 子组件索引
      • slot插槽
      • 具名slot
      • 使用component标签挂载模板
      • $nextTick
    • 自定义指令
    • 虚拟dom
    • vue-router
      • 安装vue-router
      • 配置vue-router
    • 配置跳转
      • 方式一,router-link
      • 方式二,api跳转
      • router钩子函数
        • beforeEach
        • afterEach
    • vuex
      • 安装vuex
      • 配置vuex
      • 使用vuex,创建数据
        • 获取vuex中的数据
      • 使用mutations修改states的数据
      • commit接收对象
      • getters
      • 异步操作数据使用actions
      • modules状态区分
    • 中央事件总线vue-bus

Vue基础

数据绑定

通过{{}}可以与vue中data中的数据绑定。如果不想使用{{}}可以使用

v-pre

取消{{}}数据绑定。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>
<body>
    <id id="app">
        <span >{{ a }}</span>
        <span v-pre>{{a}}</span>
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: "#app",
           data: {
               a: '<a href="www.baidu.com" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >百度</a>'
           },
           created() {
               console.log(this);
               console.log(this.a);
               console.log(this.$el);
               // vue数据实例创建完成,数据生成
           },
           mounted() {
               console.log(this);
               console.log(this.$el);
               // 挂载el,与dom关联
           }
           
       })
    </script>
</body>
</html>
           

使用v-html输出html内容。

<id id="app">
	<span >{{ a }}</span>
    <span v-pre>{{a}}</span>
    <span v-html='a'></span>
</id>

<script src="./js/vue.min.js"></script>
<script>
   let vue = new Vue({
       el: "#app",
       data: {
           a: '<a href="www.baidu.com" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >百度</a>'
       }
   })
</script>
           

过滤器

filters属性加上|操作符实现过滤:

<id id="app">
		<!-- name 即为要过滤的数据  | 表示要使用过滤 formartName表示使用的哪个过滤器 -->
       {{ name | formartName}}
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: "#app",
           data: {
               name: 'zs'
           },
           // 在filters中使用过滤器方法
           filters: {
               formartName(value) { // value就是需要过滤的数据
                    return "@_" + value + "[email protected]";
               }
           }
       })
    </script>
           

可以指定使用多个过滤器,也可以给过滤器传递参数:

<id id="app">
        可以使用多个过滤器,并且还能给过滤器传递参数
       {{ name | formartName | formartName1('*')}}
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: "#app",
           data: {
               name: 'zs'
           },
           filters: {
               formartName(value) { // value就是需要过滤的数据
                    return "@_" + value + "[email protected]";
               },
               formartName1(value, param) {
                    return value + '->' + param;
               }
           }
       })
    </script>
           

指令

使用

v-show

,如果为false时,只是设置了对应的元素的

display

属性为none:

<id id="app">
       <p v-show="isShow">v-show的使用</p>
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isShow: true
           }
       })
    </script>
           

v-bind

作数据绑定,可以为元素动态绑定一个属性。

<id id="app">
		为p标签绑定了一个name属性,name属性的值就是data数据中text对应的值
       <p v-bind:name='text' v-show="isShow">v-show的使用</p>
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isShow: true,
               text: '_text'
           }
       })
    </script>
           

v-on

指令,可以用来监听事件,其后接一个methods中定义的方法或者一个表达式。

<id id="app">
       <p v-bind:name='text' v-show="isShow" v-on:click="isShow = false">v-show的使用</p>
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isShow: true,
               text: '_text'
           }
       })
    </script>
           

计算属性

computed

时计算属性,计算属性也是一个属性,类似于data中的数据,计算属性是一个函数,计算属性的值是函数的返回值。

<id id="app">
       {{ fullName }}
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               firstName: 'Jhon',
               lastName: 'Cena'
           },
           computed: {
               fullName() {
                   return this.firstName + " " + this.lastName;
               }
           }
       })
    </script>
           

计算属性的getter、setter方法

计算属性有getter和setter方法,分别用于读取和设置计算属性的值。

<id id="app">
       {{ fullName }}
    </id>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               firstName: 'Jhon',
               lastName: 'Cena'
           },
           computed: {
               fullName: {
                   get() {
                       return this.firstName + " " + this.lastName;
                   },
                   set(value) {
                        let vs = value.split(' ');
                        this.firstName = "*" + vs[0];
                        this.lastName = vs[1];
                   }
               }
           }
       })
       app.fullName = 'zhang san';
    </script>
           

计算属性是依赖其他属性的,只要其他属性发生改变,计算属性就会跟着发生变化。setter属性可以接收一个参数,这个参数接收了并不是一定能改变计算属性的值,而是根据参数,去改变对应的计算属性依赖的值,依赖的值改变,getter方法会返回对应格式的数据。

计算属性扩展

计算属性可以依赖其他计算属性,计算属性也可以依赖其他实例数据,这里演示计算属性依赖其他实例数据。

<div id="app1">
        {{ msg }}
    </div>
    <div id="app2">
        {{message}}
    </div>
    
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app1 = new Vue({
           el: '#app1',
           data: {
               msg: 'message'
           }
       });
       let app2 = new Vue({
           el: '#app2',
           computed: {
               message() {
                   return app1.msg.split('').reverse().join('');
               }
           }
       })
       app1.msg = 'hello world!';
       
    </script>
           

计算属性缓存

计算属性(computed)类似于方法(methods),但是方法每次调用都会被执行,而计算属性则不同,只有在计算属性所依赖的数据发生改变时才会执行。

<div id="app1">
		计算属性是一个属性,可以直接使用,methods是方法,需要调用
        {{ cTime }},<br/> {{ mTime() }}
    </div>
  
    <script src="./js/vue.min.js"></script>
    <script>
       let app1 = new Vue({
           el: '#app1',
           data: {
               data: new Date()
           },
           computed: {
                cTime() {
                    return this.data + " --- ";
                }
           },
           methods: {
               mTime() {
                   return new Date();
               }
           }
       });
           

v-bind

绑定class

使用对象语法绑定class:

<div id="app">
        <span :class="{ 'red': isRed, 'error': isError}">这段话的颜色</span>
    </div>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isRed: true,
               isError: true,
               active: 'active',
               primary: 'primary'
           }
       })
    </script>
           

<span :class="{ ‘red’: isRed, ‘error’: isError}">这段话的颜色</span>

,这里为class绑定一个对象,对象的属性名将作为class属性的值,当且仅当对象属性的值为true时,才会被应用。

使用数组语法绑定class

使用数组语法,可以嵌套对象语法。

<div id="app">
        <span :class="[{ 'red': isRed, 'error': isError}, active, primary]">这段话的颜色</span>
    </div>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               isRed: true,
               isError: true,
               active: 'active',
               primary: 'primary'
           }
       })
    </script>
           

要绑定多个class属性需要使用对象语法或者数组语法,如果都不使用,而是直接使用数据,最多只能有一个数据。

错误写法:

正确写法(只能有一个):

绑定内联样式

对象语法,与绑定class不同的是,对象属性作为内联样式属性,数据的值作为样式的值,而不是根据true和false来确定应用谁

<div id="app">
        <span :style="{'color': red, 'fontSize': fontSize + 'px'}">这段话的颜色</span>
    </div>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               red: 'red',
               fontSize: 20
           }
       })
    </script>
           

使用数组语法绑定多个样式

<div id="app">
        <span :style="[color, font]">这段话的颜色</span>
    </div>
    
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               color: {
                   color: 'red',
                   background: 'green'
               },
               font: {
                   fontSize: 20 + 'px'
               }
           }
       })
    </script>
           

内置指令

v-cloak

v-cloak

的作用:如果网速较慢等情况下,数据加载较慢,{{data}}可能会直接显示在页面上,而v-cloak的作用就是阻止这种情况的发生。使用v-cloak时需要配合下面css样式:

[v-cloak] {
            display: none;
        }
           
<div id="app">
        <span v-cloak>{{ msg }}</span>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: 'message'
           }
       })
    </script>
           

v-pre

v-pre

的作用:{{data}}是取数据,而有时候我们需要原样输出,即{{}}不具备任何功能,这是就可以使用v-pre

<div id="app">
        <span v-pre>{{ msg }}</span>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: 'message'
           }
       })
    </script>
           

v-once

使用v-once,数据只被渲染一次,之后数据发生变化使用了v-once的数据也不会被渲染

<div id="app" @click="changeMsg">
        <span>{{ msg }}</span><br/>
        <span v-once>{{ msg }}</span>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: 'message'
           },
           methods: {
               changeMsg() {
                   this.msg = this.msg.split('').reverse().join('');
               }
           }
       })
           

v-if、v-else-if、v-else

v-if和

v-show

的区别是,v-if不会加载html标签,v-show时设置css样式dispaly为none,

v-show

多用于频繁操作的场景。

<div id="app">
        <span v-if='status == 1'>1</span>
        <span v-else-if='status == 2'>2</span>
        <span v-else-if='status == 3'>3</span>
        <span v-else>4</span>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               status: 3
           }
       })
    </script>
           

可以使用

<template>

标签作为v-if的载体,

<template>

最终不会被加载到html中。

注:使用v-if时vue会尽可能的复用组件,比如下面代码,点击切换的时候,vue做的其实就是把相同标签的不同的地方更换了,即把手机号换成了邮箱,name属性的phone换成了email:

<div id="app">
        <template v-if='status === 1'>
            <label>手机号:</label>
            <input type="text" name="phone">
        </template>
        <template v-if='status === 2'>
            <label>邮箱:</label>
            <input type="text" name="emial">
        </template>
        <button @click='change'>切换</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               status: 1
           },
           methods: {
               change() {
                   this.status = this.status === 1 ? 2 : 1;
               }
           }
       })
    </script>
           

如果不需要组件被复用,可以组件添加一个key属性,属性的值必须是唯一的。

v-for

v-for用来遍历数组或者对象属性,也可以结合template标签使用。

遍历数组时,有两个参数可选,第一个是每一项的数据,第二个是索引。遍历对象时,第一个参数是对象的属性名,第二个参数是对象属性值,第三个参数是索引:

<div id="app">
       <ul>
           <li v-for="(a, index) of arr"> {{ a }} -- {{ index }}</li>
       </ul>
       <template v-for="(key, value, index) of person">
            {{ index }} : {{ key }} -> {{ value }}<br>
       </template>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               arr: [1, 3, 5, 7],
               person: {
                   name: 'zs',
                   age: 18,
                   address: 'China'
               }
           }
       })
           

v-for迭代整数

<div id="app">
   <span v-for="(item, index) of integer">{{index}} : {{item}} /</span>
</div>
<script src="./js/vue.min.js"></script>
<script>
   let app = new Vue({
       el: '#app',
       data: {
         integer: 10
       }
   })
</script>
           

更新数组触发数据改变的方法

  • push():向原数组末尾增加一个元素

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.push(6);
               }
           }
       })
           
  • pop():从数组末尾删除一个元素

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.pop();
               }
           }
       })
    </script>
           
  • shift():从数组开头删除一个元素
<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.shift();
               }
           }
       })
    </script>
           
  • unshift():向数组开始位置添加一个元素
<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.unshift(1);
               }
           }
       })
    </script>
           
  • splice():改变数组长度

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [1,2,3,4,5]
           }, 
           methods: {
               change() {
                 this.arr.splice(2);
               }
           }
       })
    </script>
           
  • sort():数组排序
<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               change() {
                this.arr.sort((a, b) => {
                    // a-b就相当于a要大于b,升序排序
                    return a - b;
                })
               }
           }
       })
    </script>
           
  • reverse() :反转数组

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               change() {
                this.arr.reverse();
               }
           }
       })
    </script>
           
  • filter():数组过滤,不改变原数组,返回一个新的数组

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               
               change() {
                    console.log(this.arr);
                    // 不改变原数组,产生一个新的数组
                    this.arr = this.arr.filter(function(data) {
                        return data > 2;
                    });
               }
           }
       })
    </script>
           
  • concat():连接数组,把一个数组追加大当前数组后,不改变原有数组,产生新的数组

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               
               change() {
                    let arr2 = ['a', 'b', 'c'];
                    this.arr = this.arr.concat(arr2);
               }
           }
       })
    </script>
           
  • slice():根据下脚标查找元素,不改变原有数组,产生一个新数组并返回

    示例:

<div id="app" >
       {{arr}}
       <button @click="change">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             arr: [7,2,1,4,5]
           }, 
           methods: {
               
               change() {
                    let arr2 = [2,4];
                    // 查找数组中索引大于等于2的所有元素,组成一个新数组并返回
                    // this.arr = this.arr.slice(2);
                    // 查找下脚标大于等于0小于1的元素,组成一个新数组并返回
                    this.arr = this.arr.slice(0,1);
               }
           }
       })
    </script>
           

v-on

监听事件:

<div id="app" >
       {{count}}
       <button @click="count++">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             count: 0
           }
       })
    </script>
           

绑定使用方法:

<div id="app" >
       {{count}}
       可以传参,也可以传入当前事件$event
       <button @click="change('abc',$event)">change</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             count: 0
           },
           methods: {
               change(param) {
               		// 可以通过event去访问事件
                    console.log(param, event);
               }
           }
       })
   </script>
           

事件修饰符.stop,.prevent,.capture,.self,.once

  • .stop 阻止事件冒泡

    示例:点击button按钮,如果事件冒泡的话,也会触发div的单击事件,但是在button上使用.stop就会阻止事件冒泡

<div id="app" >
       {{count}}
       <div @click="count++">
            <button @click.stop=''>change</button>
       </div>
       
    </div>
           
  • .prevent 阻止事件的默认行为

    示例:

<div id="app" >
       {{count}}
       <div @click="count++">
            <a href="www.baidu.com" @click.prevent=''>change</a>
       </div>
    </div>
           
  • .capture 事件捕获模式

    下面代码先执行1后执行2,如果不适应.capture的话是先执行2后执行1

<div id="app" >
   <div @click.capture="change(1)">
        <button @click.capture='change(2)'>change</button>
   </div>
</div>
           
  • .self 元素本身触发事件时才执行
<div id="app" >
       {{count}}
       <div @click.self="count++">
       		<!--点击button不会触发div的单击事件-->
            <button @click.prevent=''>change</button>
       </div>
    </div>
           

v-model

使用v-model实现表单数据绑定,v-model可以用@input来实现。

<div id="app" >
        {{msg}}
       <input v-model="msg" placeholder="请输入...">
       <input @input="input" placeholder="请输入..." :value="msg">
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
             msg: ''
           },
           methods: {
               input(e) {
                    this.msg = e.target.value;
               }
           }
       })
    </script>
           

组件

组件注册

<div id="app" >
        <!-- 使用全局注册的组件 -->
       <my-component></my-component>
       <!-- 使用局部注册的组件 -->
       <child></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
        // 注册全局组件
        Vue.component('my-component', {
            template: '<div>xxx</div>'
        });
       let app = new Vue({
           el: '#app',
           // 注册局部组件
           components: {
               'child': {
                   template: '<div>child</div>'
               }
           }
       })
    </script>
           

挂载组件

在类似于table这样的标签中,只能使用td,tr等,不能使用自定义组件的时候,需要把组件挂载到某个节点上。

<div id="app" >
       <table>
            <!-- 通过is属性挂载组件 -->
            <tbody is='child'></tbody>
       </table>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           // 注册局部组件
           components: {
               'child': {
                   template: '<th>child</th>'
               }
           }
       })
    </script>
           

通过props传递数据:

<div id="app" >
       <table>
            <!-- 通过is属性挂载组件 -->
            <tbody is='child' message='传递数据的方式'></tbody>
       </table>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           // 注册局部组件
           components: {
               'child': {
                   props: ['message'],
                   template: '<th>{{message}}</th>'
               }
           }
       })
    </script>
           

子组件向父组件传值

<div id="app" >
        {{ msg }}
        <!-- 通过子组件定义的事件来接收子组件传递的值 -->
       <child @data='changeData' message='h'></child>
    
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: 'o'
           },
           methods: {
                changeData(data) {
                    // data就是 子组件 传递过来的数据
                    this.msg = data;
                }
           },
           // 注册局部组件
           components: {
               'child': {
                   props: ['message'],
                   template: '<div>{{message}}' +
                            '<button @click="change">传递数据</button></div>',
                   methods: {
                        change() {
                            // 子组件通过$emit传值,第一个参数是自定义事件名称,第二个参数是传的值
                            this.$emit('data','abc')
                        }
                   }
               }
           }
       })
  </script>
           

使用v-model和$emit传值

<div id="app" >
        {{msg}}
        <child v-model='msg'></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           methods: {
               changeMsg(data) {
                   this.msg = data;
               }
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">传递数据</button>',
                   methods: {
                       sendMsg() {
                           this.$emit('input', 'abc');
                       }
                   }
               }
           }
       })
    </script>
           

上面这个对应的自定义事件写法:

<div id="app" >
        {{msg}}
        <child @input='changeMsg'></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           methods: {
               changeMsg(data) {
                   this.msg = data;
               }
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">传递数据</button>',
                   methods: {
                       sendMsg() {
                           this.$emit('input', 'abc');
                       }
                   }
               }
           }
       })
    </script>
           

中央事件总线

<div id="app" >
        {{msg}}
        <child></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       // 创建一个空实例vue,只用于传递数据
       var bus = new Vue();
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           mounted() {
                let _this = this;
                // 通过这个空实例vue监听这个事件,并接收数据
                bus.$on('input', (data) => {
                    _this.msg = data;
                })
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">传递数据</button>',
                   methods: {
                       sendMsg() {
                           // 通过空实例vue注册一个事件,并传递数据
                           bus.$emit('input', 'abc');
                       }
                   }
               }
           }
       })
    </script>
           

父($parent)链传递数据

多个父组件只需要多次.$parent就可以了。但是这种子组件直接修改父组件的方式不推荐使用。(紧耦合)

<div id="app" >
        {{msg}}
        <child></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">传递数据</button>',
                   methods: {
                       sendMsg() {
                           // 直接修改父组件的数据
                           this.$parent.msg = 'hahaha';
                       }
                   }
               }
           }
       })
    </script>
           

子组件索引

<div id="app" >
        {{msg}}
        <!-- ref 为组件取一个别名 -->
        <child ref='childA'></child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let app = new Vue({
           el: '#app',
           data: {
               msg: '0'
           },
           mounted() {
                // 通过$refs.别名 去访问子组件的数据
                this.msg = this.$refs.childA.msg;
           },
           components: {
               child: {
                   template: '<button @click="sendMsg">传递数据</button>',
                   data() {
                       return {
                           msg: '12345'
                       }
                   },
                   methods: {
                       sendMsg() {
                           // 直接修改父组件的数据
                           this.$parent.msg = 'hahaha';
                       }
                   }
               }
           }
       })
    </script>
           

slot插槽

<div id="app" >
       <child>
           <!-- 向插槽内添加数据 -->
           <p>{{msg}}</p>
       </child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
           data: {
               msg: '12345'
           },
           components: {
               child: {
                //    slot作为插槽,在使用当前组件时,如果在标签内写入了内容,就替换插槽内的内容
                   template: "<div>子组件的内容:<slot>插槽</slot></div>"
               }
           }
       });
    </script>
           

具名slot

用于向指定的插槽内添加数据:

<div id="app" >
       <child>
           <!-- 向插槽内添加数据 -->
           <p>
               <!-- 向name为n2的插槽内添加数据 -->
               <div slot='n2'>{{msg}}</div>
           </p>
       </child>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
           data: {
               msg: '12345'
           },
           components: {
               child: {
                //    slot作为插槽,在使用当前组件时,如果在标签内写入了内容,就替换插槽内的内容
                   template: "<div>子组件的内容:<slot name='n1'>插槽</slot><slot name='n2'>2</slot></div>"
               }
           }
       });
    </script>
           

使用component标签挂载模板

is指定要挂载的是哪个模板,可以动态指定

:is

<div id="app" >
      <component is='child'></component>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
           data: {
               msg: '12345',
           },
           components: {
               child: {
                   name: 'child',
                   template: "<div>123</div>"
               }
           }
       });
    </script>
           

$nextTick

下面代码执行会报错:

<div id="app" >
        <div id="content" v-if='isShow'>hello world!</div>
        <button @click='isShow = false'>隐藏</button>
        <button @click='getText'>显示并获取内容</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
          data: {
                isShow: true
          },
          methods: {
              getText() {
                  this.isShow = true;
                  // this.isShow = true 此时并没有去更新dom,而是开启一个队列,在队列中处理数据(去重,得到最终改变),
                  // 不是数据改变一次,页面就渲染一次,只有所有数据最终固定后渲染数据,改变dom,所以此时去获取一个不存在的元素报错
                  // 在下一次事件循环tick完成更新
                  let msg = document.getElementById("content").innerText;
                  console.log(msg);
              }
          }
       });
    </script>
           

修改后,使用$netTick

<div id="app" >
        <div id="content" v-if='isShow'>hello world!</div>
        <button @click='isShow = false'>隐藏</button>
        <button @click='getText'>显示并获取内容</button>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
       let vue = new Vue({
           el: '#app',
          data: {
                isShow: true
          },
          methods: {
              getText() {
                  this.isShow = true;
                  // this.isShow = true 此时并没有去更新dom,而是开启一个队列,在队列中处理数据(去重,得到最终改变),
                  // 不是数据改变一次,页面就渲染一次,只有所有数据最终固定后渲染数据,改变dom,所以此时去获取一个不存在的元素报错
                  // 在下一次事件循环tick完成更新
                  // $nextTick可以知道什么时候dom更新完成
                  this.$nextTick(() => {
                    let msg = document.getElementById("content").innerText;
                    console.log(msg);
                  });
              }
          }
       });
    </script>
           

自定义指令

注册指令的两种方式

一、全局注册

Vue.directive('指令名', {
            // 指令选项
        })
           

二、局部注册

new Vue({
      el: '#app', 
        directivies: {
            '指令名': {
                // 指令选项
            }
        }
    })
           

使用 v-指令名 即可。

全局方式:

<div id="app" >
        <input v-focus>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
        Vue.directive ('focus', {
            inserted(el) {
                el.focus();
            }
        })
    </script>
           

局部方式:

<div id="app" >
        <input v-focus>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
        let app = new Vue({
            el: '#app',
            directives: {
                focus: {
                    inserted: function(el) {
                        el.focus();
                    }
                }
            }
        })
    </script>
           

虚拟dom

<div id="app" >
       <anchor :level='2' title="特性">特性</anchor>
    </div>
    <script src="./js/vue.min.js"></script>
    <script>
        Vue.component('anchor', {
            props: {
                level: {
                    type: Number,
                    required: true
                },
                title: String,
                default: ''
            },
            render: function(createElement) {
                return createElement(
                    'h' + this.level,
                    [
                        createElement(
                            'a',
                            {
                                domProps: {
                                    href: '#' + this.title
                                }
                            },
                            this.$slots.default
                        )
                    ]
                )
            }
        })
        let app = new Vue({
            el: '#app'
        })
    </script>
           

vue-router

安装vue-router

npm install vue-router --save
           

配置vue-router

import Vue from 'vue'
import App from './App.vue'
// 导入vue-router
import VueRouter from 'vue-router'
// 导入vue组件
import Index from './views/Index'
import About from './views/About'

// 配置路由和组件映射
const Routers = [
  {
    path: '/index',
    component: Index
  },
  {
    path: '/about',
    component: About
  },
  {
    path: '*',
    redirect: '/index'
  }
]
// 配置路由
const RouterConfig = {
  mode: 'history',
  routes: Routers
}
// 创建vue-router实例
const router = new VueRouter(RouterConfig)

Vue.use(VueRouter)

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router: router,
  render: h => h(App)
}).$mount('#app')

           

配置跳转

方式一,router-link

<router-view></router-view>

标签内显示组件内容,

router-link

标签类似a标签,tag标签使用与指定router-link使用哪个标签实现。

<template>
  <div id="app">
    hello
    <router-view></router-view>
    <router-link to='/index'>首页</router-link>
    <router-link to='/about' tag='span'>关于</router-link>
  </div>
</template>

<script>
export default {

}
</script>
<style scoped>
  #app {
    color: red;
  }
</style>

           

router-link

的其他属性:

replace :不会留下历史记录,回退不能回到上个页面
 <router-link replace to='/about' >关于</router-link>
           
active-class:当前router-link被选中时的类名,比如下面这个关于被选中时的class属性为about
<router-link to='/about' tag='span' replace active-class='about'>关于</router-link>
           

方式二,api跳转

this.$router.push(’/about’)

<template>
  <div id="app">
    hello
    <router-view></router-view>
    <router-link to='/index'>首页</router-link>
    <router-link to='/about' tag='span' replace active-class='about'>关于</router-link>
    <button @click="handleRouter">API跳转</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleRouter () {
     // 通过api的方式跳转
      this.$router.push('/about')
    }
  }
}
</script>
<style scoped>
  #app {
    color: red;
  }
</style>

           

$router的其他方法:

replace: 方法类似于router-link中的replace属性,this.$router.replace('/index')
go:类似于window.history.go(),表示向前或向后后退多少步。例如this.$router.go(-1)后退1页,this.$router.go(2)前进2页
           

router钩子函数

beforeEach

进入路由前beforeEach函数:

// 配置路由和组件映射
const Routers = [
  {
    path: '/index',
    meta: {
      title: '首页'
    },
    component: Index
  },
  {
    path: '/about',
    meta: {
      title: '关于'
    },
    component: About
  },
  {
    path: '*',
    redirect: '/index'
  }
]
// 配置路由
const RouterConfig = {
  mode: 'history',
  routes: Routers
}
// 创建vue-router实例
const router = new VueRouter(RouterConfig)

// 进入路由前
router.beforeEach((to, from, next) => {
  window.document.title = to.meta.title
})
           

meta字段可以自定义信息。

三个参数:

to:要跳转到的路由
from: 从哪个路由跳转的
next:函数,调用这个函数才进入下一个钩子,否则路由不跳转
           

afterEach

每一个路由中的设置

比如进入每个页面后,滚动条都在起始位置:

router.afterEach((to, from, next) => {
	window.scrollTo(0,0)
})
           

或者判断是否登录:

router.afterEach((to, from, next) => {
	if ('登录') {
		next(); // 允许路由跳转
	} else {
		next('login'); // 否则跳转到登录页面
	}
})
           

next()

函数,不接受参数,路由跳转,设置为false,路由取消跳转,参数为具体路由,跳转到指定路由。

vuex

安装vuex

npm install vuex --save
           

配置vuex

在main.js中配置

import Vuex from 'vuex'

Vue.use(Vuex)

// 配置vuex
const store = new Vuex.Store({

})
new Vue({
  el: '#app',
  router: router,
  store: store, // 配置vuex
  render: h => h(App)
}).$mount('#app')
           

使用vuex,创建数据

数据保存在state字段:

const store = new Vuex.Store({
  state: {
    count: 0
  }
})
           

获取vuex中的数据

通过$store.state.xxx访问数据

<template>
    <div>
        首页 {{ $store.state.count }}
        <button @click="handleCount">加一</button>
    </div>
</template>
<script>
export default {
  methods: {
    handleCount () {
      this.$store.state.count++
    }
  }
}
</script>

           

这样访问每次都会调用

$store.state.xxx

,可以把这个作为计算属性

<template>
    <div>
        首页 {{ count }}
        <button @click="handleCount">加一</button>
    </div>
</template>
<script>
export default {
  computed: {
    count () {
      return this.$store.state.count
    }
  },
  methods: {
    handleCount () {
      this.$store.state.count++
    }
  }
}
</script>

           

使用mutations修改states的数据

state中的数据不建议直接修改,而是通过mutations属性定义方法来修改

// 配置vuex
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    },
    decrease (state, n = 1) {
      state.count -= n
    }
  }
})
           

在组件中掉哟mutations中的方法来改变数据,调用mutations中的数据要使用commit来调用:

<template>
    <div>
        首页 {{ count }}
        <button @click="handleCountA">加</button>
        <button @click="handleCountD">减</button>
    </div>
</template>
<script>
export default {
  computed: {
    count () {
      return this.$store.state.count
    }
  },
  methods: {
    handleCountA () {
      this.$store.commit('increment')
    },
    handleCountD () {
      this.$store.commit('decrease', 2)
    }
  }
}
</script>

           

commit接收对象

main.js中定义方法:

mutations: {
    increment (state) {
      state.count++
    },
    decrease (state, n = 1) {
      state.count -= n
    },
    // param作为一个对象
    change (state, param) {
      state.count += (param.count1 - param.count2)
    }
  }
           

在组件中调用,type就是要调用的方法名,其他的就是具体的参数:

changeCount () {
  this.$store.commit({
    type: 'change',
    count1: 1,
    count2: 5
  })
}
           

在mutations中不要做异步操作,commit后数据不能及时跟新。

getters

getters类似于计算属性

需求:对一个数组进行过滤,去大于10的数

state: {
    count: 11,
    list: [1, 3, 5, 7, 10, 11, 13, 15]
  },
getters: {
    listFilter: state => state.list.filter(data => data > 10),
    // getters中的数据也可以访问其他getters中的数据
    equalseCount: (state, getters) => getters.listFilter.filter(data => data === state.count)
  },
           

访问getter数据:

getter中的数据 {{ $store.getters.listFilter }} -> {{ $store.getters.equalseCount}}
           

异步操作数据使用actions

定义actions

mutations: {
    increment (state) {
      state.count++
    },
    decrease (state, n = 1) {
      state.count -= n
    },
    change (state, param) {
      state.count += (param.count1 - param.count2)
    }
  },
  actions: {
    increment (context, param) {
      context.commit('change', param)
    }
  }
           

调用actions要使用dispatch方法

actions () {
      this.$store.dispatch({ // 使用dispath方法调用action中的方法
        type: 'increment',
        count1: 1,
        count2: 5
      })
    }
           

异步案例:

actions:

actions: {
    asyncIncrement (context) {
      return new Promise(resolve => {
        setTimeout(() => {
          context.commit('increment')
          resolve('success')
        }, 2000)
      })
    }
  }
           

在组件中调用:

async () {
      this.$store.dispatch('asyncIncrement').then(data => console.log(data))
    }
           

数据改变用mutations,存在业务逻辑用actions

modules状态区分

如果所有的状态写在一起不容易区分,这时可以用modules来做区分:

const moduleA = {
  state: {
    count: 10
  }
}

const moduleB = {
  state: {
    count: 20
  },
  getters: {
    sumCount (state, getters, rootState) {
      return state.count + rootState.b.count + rootState.count
    }
  }
}

// 配置vuex
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  },
  state: {
    count: 11,
    list: [1, 3, 5, 7, 10, 11, 13, 15]
  },
}
           

获取,要注意的是 模块内部的 action、mutation、和 getter 注册在全局命名空间,不能使用模块名.getters等方式去调用

<template>
    <div>介绍 {{ $store.state.count }}
        moduleB中的Count {{ $store.state.b.count }}
        moduleB中的sumCount {{ $store.getters.sumCount }}
    </div>
</template>
<script>
export default {
}
</script>

           

中央事件总线vue-bus

新建一个vue-bus.js文件:

const install = function (Vue) {
    const Bus = new Vue({
        methods: {
            emit(event, ...args) {
                this.$emit(event, args)
            },
            on(event, callback) {
                this.$on(event, callback);
            },
            off(event, callback) {
                this.off(event, callback)
            }
        }
    })
    Vue.prototype.$bus = Bus
}
export default install

           

在main.js中引入并使用:

import VueBus from './vue-bus'

Vue.use(VueBus)
           

在组件中使用-发送数据:

<template>
    <div id="app">
        <img alt="Vue logo" src="./assets/logo.png">
        <button @click="handleNum">click</button>
        <HelloWorld/>
    </div>
</template>

<script>
    import HelloWorld from './components/HelloWorld.vue'

    export default {
        name: 'app',
        components: {
            HelloWorld
        },
        methods: {
            handleNum() {
                this.$bus.emit('add', 10);
            }
        }
    }
</script>

<style>

</style>

           

获取数据:

<template>
    <div class="hello">
        <h1>{{ number }} </h1>
    </div>
</template>

<script>
    export default {
        name: 'HelloWorld',
        data() {
            return {
                number: 0
            }
        },
        methods: {
            handle(num) {
                let data = parseInt(num)
                this.number += data
            }
        },
        created() {
            this.$bus.on('add', this.handle)
        },
        beforeDestroy() {
            this.$bus.off('add', data => console.log(data))
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

           
下一篇: Vue基础-1