这篇文章主要介绍了vue的通过ref获取DOM元素以及获取组件的引用,vue路由的认识以及watch的使用方法。以及watch监听路由变化事件,computed的用法,最后将watch,computed,methods做了对比。

1. vue中的$refs的使用

  • 1.1 $refs

    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
    <div id="app">
    <!--ref属性一定要有,后面才能调用-->
    <com4 ref="mycom4"></com4>
    <h4 ref="myh4">我是h4内容</h4>
    <input type="button" value="click me" @click="show">
    </div>
    <script src="./lib/vue-2.4.0.js"></script>
    <script>
    let com4 = {
    template: '<h3>我是组件内容</h3>',
    data(){
    return {
    msg: 'son msg'
    }
    },
    methods: {
    display(){
    console.log('调用了display方法');
    }
    }
    };

    let vm = new Vue({
    el: '#app',
    data: {},
    methods: {
    show(){
    // 一旦标签中定义了 ref 属性,$refs中就有了一个对应的键,通过这个键可以调方法等操作
    // console.log(this.$refs.myh4.innerText);
    // console.log(this.$refs.mycom4.msg);
    this.$refs.mycom4.display();
    }
    },
    components: {
    com4 // 内部组件com4
    }
    });
    </script>

2. VueRouter

  • 2.0 前后端路由的区别

    a. 后端路由:对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
    b. 前端路由:对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现;
    c. 在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);

  • 2.1 路由传参

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    <!--两种传递参数的方法,一种是query查询?传参,另一种是动态传值 利用params查询-->  
    <div id="app">
    <!-- 如果在路由中,使用 查询字符串,给路由传递参数则不需要修改路由规则的 path 属性 -->
    <router-link to="/login?id=8&name=tom">登录</router-link>
    <!--<router-link to="/login/10/tom">登录</router-link>-->
    <router-link to="/register">注册</router-link>

    <transition mode="out-in">
    <router-view></router-view>
    </transition>
    </div>
    <script src="./lib/vue-2.4.0.js"></script>
    <script src="./lib/vue-router-3.0.1.js"></script>
    <script>
    let login = {
    // 通过 $route.query 获取url传递的值
    template: '<h2>登录模块{{ msg }} --- {{ $route.query.id }} --- {{ $route.query.name }}</h2>',
    // template: '<h2>登录模块{{ msg }} --- {{ $route.params.id }} --- {{ $route.params.name }}</h2>',
    data(){
    return {
    msg: 'son message'
    }
    },
    created(){
    console.log(this.$route.query.name);
    }
    };
    let register = {
    template: '<h2>注册模块</h2>'
    };

    let router = new VueRouter({
    routes: [
    {path: '/', redirect: '/login'}, // 默认到登录模块,这个重定向和node中不同
    {path: '/login', component: login},
    // {path: '/login/:id/:name', component: login}, // 路由规则中定义参数
    {path: '/register', component: register}
    ],
    linkActiveClass: 'myClass' // 点解链接选中的class,替代默认值router-link-active
    });

    let vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    //router: router // 使用 router 属性来使用路由规则,也可以简写成下面格式
    router // 路由挂载到vm实例上
    });
    </script>
  • 2.2 路由嵌套-使用children属性

    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
    39
    40
    41
    42
    43
    44
    45
    46
    <div id="app">
    <router-link to="/user">user</router-link>
    <router-view></router-view>
    </div>
    <template id="tpl">
    <div>
    <h2>这是 user 组件内容</h2>
    <!--使用 tag 属性来指定router-link渲染的标签类型,eg:下面的login渲染成span-->
    <router-link to="/user/login" tag="span">login</router-link>
    <router-link to="/user/register">register</router-link>
    <router-view></router-view>
    </div>
    </template>
    <script src="./lib/vue-2.4.0.js"></script>
    <script src="./lib/vue-router-3.0.1.js"></script>
    <script>

    let user = { // 用户组件
    template: '#tpl'
    };
    let login = { // 用户登录组件
    template: '<h3>登录组件内容</h3>'
    };
    let register = { // 用户注册组件
    template: '<h3>注册组件内容</h3>'
    };

    let router = new VueRouter({
    routes: [
    {
    path: '/user',
    component: user,
    children: [ //使用children实现子路由,子路由的path前不要带 /,否则会以根路径开始请求
    {path: 'login', component: login},
    {path: 'register', component: register}
    ]
    }
    ]
    });
    let vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    router // 挂载路由到vm实例
    });
    </script>
  • 2.3 命名视图实现经典布局

    除了命名路由外还有一种配置路由的方式,叫命名视图。命名视图就是在单个路由可以定义多个命名组件。以前我们用一个component对应一个组件的名称。命名视图允许在一个根路径下定义了两个命名的组件。注意!这里components(需要加s)

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    <style>
    .header {
    height: 100px;
    background: lightcoral;
    }
    .container {
    display: flex;
    height: 450px;
    }
    .left {
    flex: 1;
    background: lightgray;
    }
    .main {
    flex: 4;
    background: lightseagreen;
    }
    </style>
    <!--分割线---------------------------->
    <div id="app">
    <router-view></router-view>
    <div class="container">
    <router-view name="left"></router-view>
    <router-view name="main"></router-view>
    </div>
    </div>
    <script src="./lib/vue-2.4.0.js"></script>
    <script src="./lib/vue-router-3.0.1.js"></script>
    <script>
    let header = {
    template: '<div class="header">我是头部</div>'
    };
    let leftBox = {
    template: '<div class="left">我是侧边栏</div>'
    };
    let mainBox = {
    template: '<div class="main">我是主题部分</div>'
    };

    let router = new VueRouter({
    routes: [
    {
    path: '/',
    components: {
    // 单个路由可以定义多个命名组件,这些组件将用相应的名称呈现到<router-view>s中。
    default: header, // 默认的
    left: leftBox, // 通过name属性<router-view name="left"></router-view>使用
    main: mainBox
    }
    }
    ]
    });
    let vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    router // 路由挂载到vm上
    });
    </script>

3. watch的使用方法

  • 3.1 在vue中,使用watch来响应数据的变化。watch的用法大致有三种。下面代码是watch的一种简单的用法:

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    <div id="app">
    <input type="text" v-model="firstName">
    <input type="text" v-model="lastName">
    <span>{{ fullName }}--- {{ cityName.name }}</span>
    </div>
    <script src="./lib/vue-2.4.0.js"></script>
    <script>
    let vm = new Vue({
    el: '#app',
    data: {
    cityName: {id: 1, name: 'shanghai'},
    firstName: 'lee',
    lastName: 'bruce',
    fullName: 'bruce - lee'
    },
    methods: {},
    // 方法1 直接写一个监听处理函数
    watch: { // 监听data中数据变化
    firstName(newVal, oldVal){
    this.fullName = newVal + ' - ' + this.lastName;
    },
    lastName(newVal, oldVal){
    this.fullName = this.firstName + ' - ' + newVal
    }
    },

    // 方法2 使用immediate和handler
    //immediate表示在watch中首次绑定的时是否执行handler,值为true则表示在watch中声明的时候,
    // 就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化的时候才执行handler。
    watch: { // 监听data中数据变化
    firstName: {
    handler(newVal, oldVal){
    this.fullName = newVal + ' - ' + this.lastName;
    },
    immediate: true
    },
    lastName: {
    handler(newVal, oldVal){
    this.fullName = this.firstName + ' - ' + newVal
    },
    immediate: true
    }
    },
    //数组(一维、多维)的变化不需要通过深度监听,对象数组中对象的属性变化则需要deep深度监听。
    //当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,
    //只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。
    //设置deep:true则可以监听到cityName.name的变化,此时会给cityName的所有属性都加上这个监听器,
    //当对象属性较多时,每个属性值的变化都会执行handler。如果只需要监听对象中的一个属性值,
    //则可以做以下优化:使用字符串的形式监听对象属性:
    watch: {
    'cityName.name': { // 这样只会给对象的某个特定的属性加监听器
    handler(newName, oldName) {
    // ...
    },
    deep: true,
    immediate: true
    }
    }
    });
    </script>
  • 3.2 watch监听路由变化

    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
    39
    <div id="app">
    <router-link to="/login">login</router-link>
    <router-link to="/register">register</router-link>
    <router-view></router-view>
    </div>
    <script src="./lib/vue-2.4.0.js"></script>
    <script src="./lib/vue-router-3.0.1.js"></script>
    <script>
    let login = {
    template: '<h2>登录界面</h2>'
    };
    let register = {
    template: '<h2>注册界面</h2>'
    };

    let router = new VueRouter({
    routes: [
    {path: '/', redirect: '/login'},
    {path: '/login', component: login},
    {path: '/register', component: register}
    ],
    linkActiveClass: 'myCls'
    });
    let vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    watch: { // 监听路由变化-参数(变化后的新值,旧值)
    '$route.path': function (newVal, oldVal) {
    if (newVal === '/login') {
    console.log('welcome to login');
    } else if (newVal === '/register') {
    console.log('welcome to register');
    }
    }
    },
    router
    });
    </script>
  • 3.3 computed 计算属性

    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
    <div id="app">
    <input type="text" v-model="a">+
    <input type="text" v-model="b">+
    <input type="text" v-model="c">=
    <input type="text" v-model="all">
    </div>
    <script src="./lib/vue-2.4.0.js"></script>
    <script>
    let vm = new Vue({
    el: '#app',
    data: {
    a: '',
    b: '',
    c: ''
    },
    methods: {},
    computed: {
    // 在computed中可以定义一些属性,叫做【计算属性】,这些属性的本质就是一个方法。
    // 使用的时候直接把他们的名称当做属性来使用,不会把他们当做方法来调用
    // 注意:只要是计算属性内部的任何数据发生变化就会重新计算这个计算属性
    // 计算属性的求值结果会被缓存起来方便下次使用,如果没有数据发生变化不会重新计算。
    'all': function () {
    return this.a + '-' + this.b + '-' + this.c;
    }
    }
    });
    </script>
  • 3.4对比 watchcomputedmethods作用

    a. computed属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
    b. methods方法表示一个具体的操作,主要书写业务逻辑;
    c. watch一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computedmethods的结合体;