[前端] VUE基础 (6) (v-router插件、获取原生DOM)

一、v-router插件

1.v-router插件介绍

v-router是vue的一个核心插件,vue+vue-router主要用来做SPA(单页面应用)的。

什么是SPA:就是在一个页面中,有多个页签,我们选择页签显示不同的内容,但页面不跳转。

例如:

[前端] VUE基础 (6) (v-router插件、获取原生DOM)_第1张图片

 

在网易云音乐的主页中,发现音乐、我的音乐、朋友这三个页签就是单页面应用。当我们切换他们时,可以观察到url的变化:

  

 

 

 这里看到的url改变(路由改变)的路由是vue-router提供的,而不是对应django的路由系统(前后端分离的项目,django只提供API的路由)。

2.下载vue-router

vue-router官方文档:https://router.vuejs.org/zh/

下载vue-router.js:https://unpkg.com/vue-router/dist/vue-router.js

由于vue-router是依赖vue.js库的,所以要先引入vue.js:

<script src="./static/vue.js">script>
<script src="./static/vue-router.js">script>

二、vue-router使用

1.使用vue-router实现页签切换

<body>
<div id="app">
div>
<script src="./static/vue.js">script>
<script src="./static/vue-router.js">script>
<script>
    // 主页组件
    const Home = {
        data() {
            return {}
        },
        template: `
            <div>
                我是Home
            </div>
        `
    }
    // 课程页面组件
    const Course = {
        data() {
            return {}
        },
        template: `
            <div>
                我是Course
            </div>
        `
    }
    // VueRouter实例,其中的routes列表属性中定义具体的路由映射,url-->组件
    const router = new VueRouter({
        routes: [
            {
                path: '/',
                component: Home
            },
            {
                path: '/course',
                component: Course
            }
        ]

    })
    let App = {
        data() {
            return {}
        },
        // 最前面一个header,提供标签,标签不是标签,而是
        // 该标签可以通过to属性的url在routes中匹配到对应的路由,然后找到对应组件,渲染到的位置
        template: `
            <div>
                <div class="header">
                    <router-link to = "/">首页</router-link>
                    <router-link to = "/course">课程</router-link>
                </div>
                <router-view></router-view>
            </div>
            `
    }
    var vm = new Vue({
        el: "#app",
        data() {
            return {}
        },
        router,
        template: `
            <div>
                <App></App>
            </div>
        `,
        components: {
            App
        }
    })
script>
body>

其中最重要的就是VueRouter实例中的routes的配置,以及App组件中使用的vue-router提供的两个全局组件

标签默认被渲染成a标签,而其中的to属性默认被渲染为a标签的href属性。

还有个最重要的就是,vue实例中的router属性,实际上是router:router(名字相同可以缩写为router)。

实现效果:

加上一些简单样式后,效果更明显:

[前端] VUE基础 (6) (v-router插件、获取原生DOM)_第2张图片

2.路由重定向

修改路由实例router,实现重定向:

const router = new VueRouter({
    routes: [
        // 当访问"/"目录时,重定向到/home
        {
            path: '/',
            redirect:'/home'
        },
        {
            path: '/home',
            component: Home
        },
        {
            path: '/course',
            component: Course
        }
    ]
})

3.命名路由

给每条路由条目添加name:

const router = new VueRouter({
    routes: [
        {
            path: '/home',
            name: 'Home',
            component: Home
        },
        {
            path: '/course',
            name: 'Course',
            component: Course
        }
    ]
})

使用的时候:

let App = {
    data() {
        return {
            home_page_name:'Home',
            course_page_name:'Course'
        }
    },
    template: `
        
:to = "{name:home_page_name}">首页 :to = "{name:course_page_name}">课程
` }

注意,这里使用了v-bind绑定了to属性,后面的对象就可以使用动态数据来指定组件了,当然也可以使用静态的字符串。例如"{name:'Home'}"。

4.动态路由匹配

直白的说就是给路由中传入动态参数,例如http://127.0.0.1:8080/user/1是访问id为1的用户信息,最后的1代表user_id,每个用户访问这个页面的路由都不一样。

完整代码:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Gouzititle>
    <style>
        .content{
            width:400px;
            height: 200px;
        }
        .header_button{
            width: 30px;
            height: 20px;
            line-height: 20px;
            background-color: brown;
        }
    style>
head>
<body>
<div id="app">
div>
<script src="./static/vue.js">script>
<script src="./static/vue-router.js">script>
<script>
    // 用户detail页面组件
    const User = {
        data() {
            return {
                user_id:null
            }
        },
        template: `
            <div class="content" style="background-color: darkgoldenrod">
                我是User-{{user_id}}页面
            </div>
        `,
        // 想要获得当前路由url中的id,使用以下操作:1.created(测试不成功)2.使用watch(成功)
        // 在User组件首次创建的时候,使用created获取url中的user_id
        created(){
            // 使用$route就可以获取当前url的路由信息,从其中可以拿到/user/1中的1
            this.user_id = this.$route.params.id;
            // 在这里使用ajax获取user_id对应的后台数据
            //todo.
        },
        // 在我们切换页签的时候,例如/user/1切换到/user/2,created默认不执行,因为vue为了提高效率内部复用了User组件,所以User组件不会重复创建,这时我们要使用watch
        watch:{
            // 侦听$route的变化,然后执行下面操作
            '$route'(to,from){
                console.log(to);  // 这个to对应/user/2的$route(我们从/user/1切换到/user/2)
                console.log(from);  // 这个from对应/user/1的$route(我们从/user/1切换到/user/2)
                this.user_id = to.params.id;
                //在这里可以发送ajax请求切换后user_id对应的用户信息
                //todo.
            }
        }
    }
    // VueRouter实例,其中的routes列表属性中定义具体的路由映射,url-->组件
    const router = new VueRouter({
        routes: [
            {
                path: '/',
                redirect: '/user'
            },
            {
                path: '/user/:id',  // 使用:id来接收id动态数据
                name: 'User',
                component: User
            }
        ]
    })
    let App = {
        data() {
            return {
                user_page_name:"User",
            }
        },
        template: `
            <div>
                <div class="header">
                    
                    <router-link class="header_button" :to = "{name:user_page_name,params:{id:1}}">用户1</router-link>
                    <router-link class="header_button" :to = "{name:user_page_name,params:{id:2}}">用户2</router-link>
                </div>
                <router-view></router-view>
            </div>
            `
    }
    var vm = new Vue({
        el: "#app",
        data() {
            return {}
        },
        router,
        template: `
            <div>
                <App></App>
            </div>
        `,
        components: {
            App
        }
    })
script>
body>
html>

流程解释:

1)第一次打开页面时,User组件被创建,其中的created方法会被执行,我们在其中使用$route获取id,并更新user_id属性。

2)由于vue内部机制为了效率,所以在我们点击切换页签(例如/user/1切换到/user/2时),User组件不会销毁再重建,而是会被复用,所以created钩子方法不会再被执行,这时,为了获取id,我们可以使用watch侦听$route的变化,然后更新user_id。

3)在created或watch获取id后,可以通过ajax请求user_id对应的用户信息,并渲染到组件的template中(这里未实现)。

4)在路由实例router中,使用":id"来构造动态路由条目。

5)在中,使用params:{id:1}来传递id的值给路由实例。

注意:$route是路由信息对象,而$router是我们定义的router对象(即VueRouter的实例)。为什么我们能在任何的组件中直接使用this.$route获取,这是因为我们的组件挂载到了父组件,从而继承下来的。

5.query参数(?userid=1)

参考4.中传递id的方式,是这样的:

<router-link :to="{name:'User',params:{id:1}}">

我们就可以实现对 http://127.0.0.1:8080/user/1 的访问。

如果想实现对 http://127.0.0.1:8080/user?userid=1:

<router-link :to="{name:'User',query:{userid:1}}">

同样的,在组件中要获取这个userid,使用:

created(){
    this.user_id = this.$route.query.userid;
},

其他操作都类似4.动态路由匹配的操作。可以参考第4节。

6.编程式导航

在前面的章节中,我们都是通过以下形式来使用路由的:

<router-link class="header_button" :to = "{name:'Home'">主页router-link>

这种方式叫做 "声明式导航"

而编程式导航的意思就是在标签或组件触发的事件函数中去跳转路由。

编程式导航的完整代码:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Gouzititle>
    <style>
        .content{
            width:400px;
            height: 200px;
        }
        .header_button{
            width: 30px;
            height: 20px;
            line-height: 20px;
            background-color: brown;
        }
    style>
head>
<body>
<div id="app">
div>
<script src="./static/vue.js">script>
<script src="./static/vue-router.js">script>
<script>
    // 主页
    const Home={
        data(){
            return {}
        },
        template:`
            <div class="content" style="background-color: darkorange">
                我是主页
            </div>
        `
    }
    // 用户detail页面组件
    const User = {
        data() {
            return {
                user_id:null
            }
        },
        // 在User页面中提供一个按钮,点击跳转到Home主页
        template: `
            <div class="content" style="background-color: darkgoldenrod">
                我是User-{{user_id}}页面
                <button @click="jumpToHome">跳转到主页</button>
            </div>
        `,
        methods:{
            jumpToHome(){
                // 跳转到主页,使用$router.push()
                this.$router.push({
                    name:'Home'
                });
            }
        },
        created(){
            this.user_id = this.$route.params.id;
            //todo.
        },
        watch:{
            '$route'(to,from){
                this.user_id = to.params.id;
                //todo.
            }
        }
    }
    const router = new VueRouter({
        routes: [
            {
                path: '/',
                redirect: '/user'
            },
            {
                path: '/home',  // 使用:id来接收id动态数据
                name: 'Home',
                component: Home
            },
            {
                path: '/user/:id',  // 使用:id来接收id动态数据
                name: 'User',
                component: User
            }
        ]
    })
    let App = {
        data() {
            return {
                home_page_name:"Home",
                user_page_name:"User"
            }
        },
        template: `
            <div>
                <div class="header">
                    <router-link class="header_button" :to = "{name:home_page_name}">主页</router-link>
                    
                    <router-link class="header_button" :to = "{name:user_page_name,params:{id:1}}">用户1</router-link>
                    <router-link class="header_button" :to = "{name:user_page_name,params:{id:2}}">用户2</router-link>
                </div>
                <router-view></router-view>
            </div>
            `
    }
    var vm = new Vue({
        el: "#app",
        data() {
            return {}
        },
        router,
        template: `
            <div>
                <App></App>
            </div>
        `,
        components: {
            App
        }
    })
script>
body>
html>

编程式导航很简单。就是在某个标签或组件的事件中去跳转页面,使用路由实例$router的push方法,传入路由条目的名称即可,$router.push({name:'Home'})。

7.嵌套路由

为了实现多级路由,例如/user/1/info和/user/1/detail。我们在路由中可以按如下定义:

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User,
      children: [
        {
          // 当 /user/:id/info 匹配成功,
          // UserInfo 会被渲染在 User 的 
          path: 'info',
          component: UserInfo
        },
        {
          // 当 /user/:id/detail 匹配成功
          // UserDetail 会被渲染在 User 的 
          path: 'detail',
          component: UserDetail
        }
      ]
    }
  ]
})

如代码所示,UserInfo组件和UserDetail组件都是在User组件中使用的,而User组件是在App组件中使用的。这样,我们就可以在查看user_id=1的用户页面,切换显示UserInfo或UserDetail组件。

但在这种路由情况向,如果我们只访问/user/1的话,页面不会有渲染,这是我们可以设置一个空的子路由来渲染点内容:

const router = new VueRouter({
  routes: [
    {
      path: '/user/:id', component: User,
      children: [
        // 当 /user/:id 匹配成功,
        // UserHome 会被渲染在 User 的 
        { path: '', component: UserHome },

        // ...其他子路由
      ]
    }
  ]
})

完整代码:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>嵌套路由title>
    <style>
        .content{
            width:400px;
            height: 200px;
        }
        .header_button{
            width: 30px;
            height: 20px;
            line-height: 20px;
            background-color: brown;
        }
    style>
head>
<body>
<div id="app">
div>
<script src="./static/vue.js">script>
<script src="./static/vue-router.js">script>
<script>
    // User组件下的使用的子组件UserHome,用于请求/user/id/时
    const UserHome = {
        data(){
            return {}
        },
        template:`
            <div class="content" style="background-color: yellow">
                我是UserHome页面
            </div>
        `
    }
    // User组件下的使用的子组件UserInfo,用于请求/user/id/info/时
    const UserInfo = {
        data(){
            return {}
        },
        template:`
            <div class="content" style="background-color: darkorange">
                我是UserInfo子页面
            </div>
        `
    }
    // User组件下的使用的子组件UserDetail,用于请求/user/id/detail/时
    const UserDetail = {
        data(){
            return {}
        },
        template:`
            <div class="content" style="background-color: darkorange">
                我是UserDetail子页面
            </div>
        `
    }
    // User组件
    const User = {
        data() {
            return {
                user_id:''
            }
        },
        // 在User页面中提供一个按钮,点击跳转到Home主页
        template: `
            <div class="content" style="background-color: darkgoldenrod">
                我是User-{{user_id}}页面
                <button @click="jumpToInfo">跳转到Info</button>
                <button @click="jumpToDetail">跳转到Detail</button>
                <br>
                <router-view></router-view>
            </div>
        `,
        methods:{
            jumpToInfo(){
                // 跳转到主页,使用$router.push()
                this.$router.push({
                    path:'/user/'+this.$route.params.id+'/info/'
                })
            },
            jumpToDetail(){
                // 跳转到主页,使用$router.push()
                this.$router.push({
                    path:'/user/'+this.$route.params.id+'/detail/'
                })
            }
        },
        created(){
            this.user_id = this.$route.params.id;
            //todo.
        },
        watch:{
            '$route'(to,from){
                this.user_id = to.params.id;
                //todo.
            }
        }
    }
    const router = new VueRouter({
        routes: [
            {
                path: '/user/:id',  // 使用:id来接收id动态数据
                name: 'User',
                component: User,
                // /user/:id下的子路由条目,/user/id/info和/user/id/detail
                children: [
                    // 空路由,当请求/user/id/时,渲染UserHome
                    {
                        path: '',
                        component: UserHome
                    },
                    {
                      // 当 /user/:id/info 匹配成功,
                      // UserInfo 会被渲染在 User 的 
                      path: 'info',
                      component: UserInfo
                    },
                    {
                      // 当 /user/:id/detail 匹配成功
                      // UserDetail 会被渲染在 User 的 
                      path: 'detail',
                      component: UserDetail
                    }
                ]
            }
        ]
    })
    let App = {
        data() {
            return {
                user_page_name:"User",
                // 假设有[1,2,3,4,5,6]用户
                user_list:[1,2,3,4,5,6]
            }
        },
        // 通过user_list中的user_id,使用v-for循环生成用户切换页签,点击页签按钮,使用编程式导航切换组件
        template: `
            <div>
                <div class="header">
                    <button v-for="id in user_list" :key='id' @click="jumpToPage(id)">User{{id}}</button>
                </div>
                <router-view></router-view>
            </div>
            `,
        methods:{
            // 编程式导航切换组件
            jumpToPage(id){
                this.$router.push({
                    path:'/user/'+id
                })
            }
        }
    }
    var vm = new Vue({
        el: "#app",
        data() {
            return {}
        },
        router,
        template: `
            <div>
                <App></App>
            </div>
        `,
        components: {
            App
        }
    })
script>
body>
html>

实现效果:

[前端] VUE基础 (6) (v-router插件、获取原生DOM)_第3张图片

8.命名视图

前面我们使用的路由条目中,都是一个path对应一个component。

当我们在一个组件中可能会使用多个子组件时,例如在User组件中,不是UserInfo和UserDetail之间切换,而是同时显示两个子组件,则需要命名视图:

const router = new VueRouter({
    routes: [
        {
            path: '/user/:id',  // 使用:id来接收id动态数据
            name: 'User',
            component: User,
            // /user/:id下的子路由条目,/user/id/info和/user/id/detail
            children: [
                {
                    path: '',
                    components: {
                        default: UserHome,
                    }
                },
                {
                    // 当 /user/:id/info 匹配成功,
                    // UserInfo 会被渲染在 User 的 
                    path: 'info_detail',
                    components: {
                        default: UserInfo,
                        detail: UserDetail
                    }
                }
            ]
        }
    ]
})

由于一个组件中要使用多个子组件,则除了一个默认的default子组件,其余都要指定名称。注意,这里是components,而不是component。

既然路由中都指定了多个子组件,那么在使用的地方也要有多个标签:

const User = {
    data() {
        return {
            user_id: ''
        }
    },
    // 在User页面中提供一个按钮,点击跳转到Home主页
    template: `
        <div class="content" style="background-color: darkgoldenrod">
            我是User-{{user_id}}页面
            <button @click="jumpToInfoDetial">跳转到Info_Detailbutton>
            <br>
            <router-view>router-view>
            <router-view name="detail">router-view>
        div>
    `,
    methods: {
        jumpToInfoDetial() {
            // 跳转到主页,使用$router.push()
            this.$router.push({
                path: '/user/' + this.$route.params.id + '/info_detail/'
            })
        }
    },
    created() {
        this.user_id = this.$route.params.id;
        //todo.
    },
    watch: {
        '$route'(to, from) {
            this.user_id = to.params.id;
            //todo.
        }
    }
}

除了default的子组件不用执行name属性,其余都要指定name属性。

完整代码:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>命名视图title>
    <style>
        .content {
            width: 400px;
            height: 200px;
        }

        .header_button {
            width: 30px;
            height: 20px;
            line-height: 20px;
            background-color: brown;
        }
    style>
head>
<body>
<div id="app">
div>
<script src="./static/vue.js">script>
<script src="./static/vue-router.js">script>
<script>
    // User组件下的使用的子组件UserHome,用于请求/user/id/时
    const UserHome = {
        data() {
            return {}
        },
        template: `
            <div class="content" style="background-color: yellow">
                我是UserHome页面
            </div>
        `
    }
    // User组件下的使用的子组件UserInfo,用于请求/user/id/info/时
    const UserInfo = {
        data() {
            return {}
        },
        template: `
            <div class="content" style="background-color: darkorange">
                我是UserInfo子页面
            </div>
        `
    }
    // User组件下的使用的子组件UserDetail,用于请求/user/id/detail/时
    const UserDetail = {
        data() {
            return {}
        },
        template: `
            <div class="content" style="background-color: darkorange">
                我是UserDetail子页面
            </div>
        `
    }
    // User组件
    const User = {
        data() {
            return {
                user_id: ''
            }
        },
        // 在User页面中提供一个按钮,点击跳转到Home主页
        template: `
            <div class="content" style="background-color: darkgoldenrod">
                我是User-{{user_id}}页面
                <button @click="jumpToInfoDetial">跳转到Info_Detail</button>
                <br>
                <router-view></router-view>
                <router-view name="detail"></router-view>
            </div>
        `,
        methods: {
            jumpToInfoDetial() {
                // 跳转到主页,使用$router.push()
                this.$router.push({
                    path: '/user/' + this.$route.params.id + '/info_detail/'
                })
            }
        },
        created() {
            this.user_id = this.$route.params.id;
            //todo.
        },
        watch: {
            '$route'(to, from) {
                this.user_id = to.params.id;
                //todo.
            }
        }
    }
    const router = new VueRouter({
        routes: [
            {
                path: '/user/:id',  // 使用:id来接收id动态数据
                name: 'User',
                component: User,
                // /user/:id下的子路由条目,/user/id/info和/user/id/detail
                children: [
                    {
                        path: '',
                        components: {
                            default: UserHome
                        }
                    },
                    {
                        // 当 /user/:id/info 匹配成功,
                        // UserInfo 会被渲染在 User 的 
                        path: 'info_detail',
                        components: {
                            default: UserInfo,
                            detail: UserDetail
                        }
                    }

                ]
            }
        ]
    })
    let App = {
        data() {
            return {
                user_page_name: "User",
                // 假设有[1,2,3,4,5,6]用户
                user_list: [1, 2, 3, 4, 5, 6]
            }
        },
        // 通过user_list中的user_id,使用v-for循环生成用户切换页签,点击页签按钮,使用编程式导航切换组件
        template: `
            <div>
                <div class="header">
                    <button v-for="(id,index) in user_list" :id="id" @click="jumpToPage">User{{id}}</button>
                </div>
                <router-view></router-view>
            </div>
            `,
        methods: {
            // 编程式导航切换组件
            jumpToPage(e) {
                this.$router.push({
                    path: '/user/' + e.target.getAttribute('id')
                })
            }
        }
    }
    var vm = new Vue({
        el: "#app",
        data() {
            return {}
        },
        router,
        template: `
            <div>
                <App></App>
            </div>
        `,
        components: {
            App
        }
    })
script>
body>
html>
View Code

实现效果:

[前端] VUE基础 (6) (v-router插件、获取原生DOM)_第4张图片

可以看到,我们点击"切换到Info_detail"按钮是,同时显示了UserInfo和UserDetail组件。

三、获取原生DOM

1.使用this.$refs获取标签或组件

我们之前在vue中获取原生的DOM,都是利用document来获取的,不是很方便。

vue为我们提供了ref属性,来方便的获取标签。

<div ref='div1'>div>
<p ref='p1'>p>
<Home ref='home1'>Home>

获取标签:

this.$refs.div1 //获取ref为'div1'的
标签 this.$refs.p1 //获取ref为'p1'的

标签 this.$refs.home1 //获取ref为'home1'的组件对象

注意this.$refs只能获取当前组件的template中的标签或组件(标识了ref属性的),例如当前组件为App组件,App组件在template中使用了User组件:

template: `
    

`,

此时,我们使用this.$refs只能获取到这个template中的div、p和User组件。因为this代表的是App组件。

假设User组件的template中使用了子组件UserInfo和UserDetail,则不能在App组件中使用this.$refs获取,而要按层级来获取:

// 在App组件中
this.$refs.user_component.$refs.userinfo_component

2.组件的成员属性

在任何一个组件中,例如App组件,我们可以使用this获取他的所有成员属性,例如:

this.$refs  // 获取当前组件template中存在ref属性的标签和组件的列表
this.$root  // 获取vue根实例
this.$parent  // 获取该组件的父组件
this.$children  // 获取该组件的子组件列表
... 

更多属性可以打印this来查看。

 

☜(ˆ▽ˆ)

你可能感兴趣的:([前端] VUE基础 (6) (v-router插件、获取原生DOM))