一、文件目录说明
main.js:应用的入口文件【js文件入口】
App.vue:根组件,整个组件的入口【组件文件入口】
new Vue({}); //Vue是构造函数,本质上是一个函数,函数就有原型prototype

加载文件不要后缀名:
resolve:{
    extensions:['.js','.vue','.json'],
    alias:{
        'vue$':'vue/dist/vue.esm.js',
        '@':resolve('src')  //@就代表了"src"这个目录
    }
}
import App from './App';  就相当于 './App.vue';
import router from './router'  //加载某个目录下的index.js文件,可以简写,就相当于 './router/index.js'

.gitignore
上传git仓库的时候,不上传某些文件,比如node_modules,因为太大了,
所以从git仓库clone文件下来的时候,首先就是要npm install,安装package.json里面定义的依赖包
然后就是npm run dev

index.js文件,定义路由(默认导出)
export default new Router({})
也可以:
let router = new Router({}) //先定义,下面导出,这样就可以用到router路由实例了
export default router

导出之后,在main.js里面引入的:import router from './router',得到一个路由实例
然后再将路由实例router注入到new Vue()这个根实例里面,就可以用到router里面的一些信息

然后在App.vue里面,写入<router-view></router-view>,展示对应渲染的组件

index.js Vue.use( Router ) //通过这种写法,就可以在每个组件里面,通过this.$router访问到当前路由实例

二、使用步骤

    安装模块
        npm install vue-router --save -dev (vue-cli脚手架里面就已经安装好了)
    引入模块
        import *VueRouter* from 'vue-router'
    作为vue的插件
        Vue.use(*VueRouter*)
    创建路由实例对象
        new VueRouter({
            //...配置参数
            mode:'history',
            routes: [
                {
                    path: '/home',
                    name: 'Home', //在后期使用这个配置好的路由时,需要用到name属性
                    component: Home
                },
                {
                    path: '/about',
                    name: 'About',
                    component: About
                },
                {
                    path: '/document',
                    name: 'Document',
                    component: Document
                } 
            ]
        })
    注入Vue选项参数
        new Vue({
            router
        })
    告诉路由渲染位置
        <router-view></router-view>

如果不注册路由组件Vue.use(VueRouter),那么报错显示没有成功注册router-view组件;
说明router-view也是一个组件,用于渲染路由组件内容

三、router-link各种配置项
路由跳转不刷新页面,默认是使用了hash值进行切换页面,因为利用hash切换页面,不是跳转,不用刷新页面
在路由配置文件里面写上:mode:'history',就使用了history模式,url里面也没有了#号
低版本使用hash模式,因为不支持history,高版本使用history模式
不能使用a标签来进行页面的切换,因为a标签有跳转链接的默认行为,会刷新页面,这样就不是一个单页应用了。
vue-router提供了一个标签,可以不刷新页面来进行页面的切换,功能就类似于优化后的a标签,凡是涉及到跳转页面的导航,都使用router-link(其实是一个组件)
<router-link to='目标链接'></router-link>,会生成a标签,同时把a标签的默认行为取消掉,并且跳转到对应的目标页

一个路径,对应渲染一个组件,实际就是分别替换<router-view></router-view>
to后面跟的属性值都是字符串

1、目标地址可以写死
<li><router-link to="/home">home</router-link></li>
2、目标地址可以动态绑定
<li><router-link :to="index">home</router-link></li>
export default{
    name:'App',
    data(){
        return {
            index:'/home'
        }
    }
}
3、目标地址可以写成对象形式
<li><router-link :to="{path:'/home'}">home</router-link></li>

4、导航不仅仅只用a标签来设置,也可以使用别的标签,如div、p、li等等
<router-link :to="index" tag="li">//写上tag="li"即可,这样里面可以添加小图标,丰富效果
    <i class="fa fa-home"></i>
    <span>home</span>
</router-link>

5、设置链接选中的状态,vue-router默认会加上router-link-active类名
可以自定义这个选中的类名,这样就不使用默认类名了
export default new Router({
    linkActiveClass:'is-active'
})
然后自己设置这个类的样式
.is-active{ background:red; }

6、不同组件,设置同一套样式
同时,每个组件也可以设置自己特有的样式
<router-view class="center" />  //这会把类名.center渲染到每个组件的根元素上,就可以所有路由组件共享一个类名

7、改变导航切换事件,默认是click,在需要这种方式切换的导航上都得添加
<router-link :to="index" tag="li" event="mouseover">

8、路径匹配不到
{
        path:'*',  //情况一、路径匹配不到,固定渲染这个组件,比如404页面
        //component:noPath

        //情况二、不渲染固定的组件,而是重定向到一个其他页面,有下面三种写法
        //redirect:'/home'
        //redirect:{path:'/home'}
        //redirect:{name:'Home'}   前面两个需要加/,后面使用name就不用加/

             //情况三、动态设置重定向的目标
        redirect:(to)=>{ 
            console.log(to) //to是目标路由对象,即要访问的路径的路由信息,见下图
            if(to.path === '/123'){
                return '/home'  //一定要加上return
            }else if(to.path === '/456'){
                return {path:'/about'}
            }else{
                return {name:'Document'}
            }
        }
    }

9、给路由设置别名
{
    path: '/home',
    name: 'Home',
    component: Home,
    alias:'/index'  //设置别名,即地址栏输入http://localhost:8080/index,也会调到home页
}
此时,home导航不会高亮,解决方法:
在router-link上设置判断:{class:$router.path === '/别名'}

vue-router教程

四、路由嵌套子路由

http://localhost:8080/about/study
/:代表根路径
/about:代表根路径下的about路径
/about/study:代表根路径下的about路径下的study
/study:代表根路径下的study

全包含匹配模式:访问/about,是相对于根路径来说的,那么根路径也会匹配到激活状态,所以home也是高亮的
vue-router教程
vue-router教程

精确匹配模式:访问/about,根路径不匹配到,在根路径上加个exact即可
<router-link class="btn" exact to='/'>home</router-link>

在path里面,'/'都是相对根路径而言,如果写子路由,那么前面就不需要加'/'了,因为以'/'都是相对于根路径的
study、work、hobby,是about路由里面的二级导航

{
    path: '/about',
    //name: 'About',  有子路由,父路由不需要设置name属性,把它给默认子路由
    component: about,
    children:[
        {
            path:'/',  //默认的子路由(不能写成 path:'work'),点击about会默认展现work组件内容
            name: 'Work',
            component:work
        },
        {
            path:'study',  //前面不需要加'/'
            name: 'Study',
            component:study
        },
        {
            path:'hobby',
            name: 'Hobby',
            component:hobby
        }
    ]
}

<template>
  <div class="about">
    <ul>
        <router-link to="/about" exact tag="li">
            <a>work</a>
        </router-link>
        <router-link to="/about/study" tag="li">
            <a>study</a>
        </router-link>
        <router-link to="/about/hobby" tag="li">
            <a>hobby</a>
        </router-link>
    </ul>
    <router-view></router-view>
  </div>
</template>

也可以使用name或者path,此时需要动态绑定v-bind
<template>
  <div class="about">
    <ul>
        <router-link :to='{path:"/about/work"}' exact tag="li">
            <a>work</a>
        </router-link>
        <router-link :to="{name:'Study'}" tag="li">
            <a>study</a>
        </router-link>
        <router-link :to="{name:'Hobby'}" tag="li">
            <a>hobby</a>
        </router-link>
    </ul>
    <router-view></router-view>
  </div>
</template>

五、命名视图:单页面多路由区域操作
在同级同时展示多个视图,而不是嵌套展示
有几个视图,就写几个<router-view name=" " />(写在父级组件内,比如about有多个视图,就写在app.vue里面,about下面的work有多个视图,router-view就写在about里面),然后通过name属性来进行区分

{
      path: '/document',
      name: 'Document',
      components:{  //注意这里是复数,加s
        default:document,  //默认的
        slider:slider  //新添加的
      }
    },
<router-view name="slider" class="center" />  //有name属性的,会匹配到components里面对应名称的组件
<router-view class="center" />  //没有name属性的会自动对应default的组件

六、滚动行为
记录页面滚动的位置,点击浏览器上的前进后退按钮,仍然会回到之前的页面位置

在index.js里面配置
export default new Router({
    mode:'history',
    linkActiveClass:'is-active',  //表示给选中的导航添加类名is-active
    scrollBehavior(to,from,savePosition){ //点击浏览器的前进后退按钮或切换导航时触发该事件
        console.log(to); //要进入的目标路由对象,即要去向哪里
        console.log(from); //离开的路由对象,即从哪里来
        console.log(savePosition);  //记录滚动条的坐标位置 只在点击前进后退按钮时才有记录

        //方法一:使用坐标值
        if(savePosition){  //写上这个代码即可,前进后退,仍然到达之前的页面位置
            return savePosition
        }else{
            return {x:0,y:0}
        }

        //方法二、使用hash值
        //<router-link :to="{path:'/document#abc'}"></router-link>
        //document页面要定位的元素  <p id="abc"></p>
        if( to.hash ){
            return {
                selector:to.hash
            }
        }

    },
    routes:[
        {
      path: '/home',
      name: 'Home',
      component: home
      meta:{  //自定义一些属性
        index:0
      }
    }
    ]
})

七、动态路径
匹配到的所有路由,全部映射到同一个组件
路径:/user/:userId/ userId为动态路径参数
获取参数:路由信息对象的params
具体例子:比如用户登录个人信息页,页面是一样的,都是同一个组件,但是不同用户要展示的信息是不一样的,这就通过userId来展示对应的信息,拿到userId就可以获取到用户的信息

vue-router教程

vue的路由有一个路由实例$router
通过在Vue根实例的router配置传入router实例
new Vue({
  el: '#app',
  router,  //也可以写成router:router
  components: { App },
  template: '<App/>'
})
在每一个组件里面,通过$router拿到router路由实例对象
$route 当前激活的路由信息对象,每个组件实例都会有,每次成功导航后都会产生一个新的对象

vue-router教程

绑定userId的写法:<router-link :to="'/user/'+item.id" v-for="item,index in userlist" />
id为1的用户页面:http://localhost:8080/user/1     不是以参数的形式:http://localhost:8080/user?userId=1 ,这个是查询字符串query
userId接收路径里传入的参数
{
    path: '/user/:userId?',//后面加个问号,正则,表示可以匹配到 /user  /user/1  /user/2  /user/3,都走User组件
    name: 'User',
    component: user
},
<template>
    <div class="user">
        <div class="user-list">
           <router-link style="padding: 0 20px;" :to="'/user/'+item.id" :key="index" v-for="item,index in userList">{{item.userName}}</router-link>
            <router-link style="padding: 0 20px;" :to="{path:'/user/'+item.id,query:{info:'follow'}}" 
                        :key="index" v-for="item,index in userList">{{item.userName}}</router-link>
        </div>
        <div class="user-list" style="font-size: 20px;" v-show="userInfo.userName">
            <p>姓名:{{userInfo.userName}}</p>
            <p>性别:{{userInfo.sex}}</p>
            <p>爱好:{{userInfo.hobby}}</p>
        </div>
        <hr />

        <div class="info-list" v-if="userInfo.userName">
            <router-link exact to="?info=follow" >follow</router-link>
            <router-link exact to="?info=share" >share</router-link>
                    <!--<router-link exact :to="{path:'',query:{info:'follow'}}">他的关注</router-link>
            <router-link exact :to="{path:'',query:{info:'share'}}">他的分享</router-link>-->
            <div>{{$route.query}}</div>
        </div>

    </div>
</template>
<script>
let data = [
        {
                id:1,
                userName:"leo1",
                sex:'男',
                hobby:'写代码'
        },
        {
                id:2,
                userName:"leo2",
                sex:'男',
                hobby:'唱歌'
        },
        {
                id:3,
                userName:"leo3",
                sex:'男',
                hobby:'读书'
        }
]
export default{
    name:"User",
    data(){
        return {
            userList:data,
            userInfo:{}
        }
    },
    watch:{  //监测Vue实例上的数据变动,这里是监听$route,路径发生变化,$route会重新赋值,监控了这个属性,会执行里面的函数
        $route(){
            this.getData();
        }
    },
    created(){  //编译之前   ajax提交信息也放在这里面
        // 渲染这个组件会调用一次这个生命周期函数
        // 复用这个组件,这个函数不会再次被调用了
        // 地址一旦发生变化,$route会重新生成一个路由信息对象
        this.getData();
    },
    methods:{
        getData(){
            let id = this.$route.params.userId;  //用户点击链接,地址栏显示,获取动态参数userId
            if(id){
                this.userInfo = this.userList.filter((item)=>{  //this.userInfo是对象,this.userList是数组,现在需要返回的是一个对象,所以取数组的第一项
                    return item.id == id;
                })[0]
            }else{
                this.userInfo = {}
            }

        }
    }
}
</script>

八、查询字符串
query字符串传参

//点击默认显示 关注切页follow
<router-link v-bind:key="index" v-for="item,index in userlist" 
:to="{path:'/user/'+item.tip+'/'+item.id,query:{info:'follow'}}" 
    {{item.userName}}
</router-link>

:to="{path:'/home'}"   //to后面跟的都是字符串,path后面跟的也是字符串,如果有变量就要使用字符串拼接

:to=" '/user/' + item.tip + '/' + item.id "
:to=" { path: '/user/' + item.tip + '/' + item.id , query : {info:'follow'} } " 

查询字符串的两种写法:

<router-link exact :to="{path:'',query:{info:'follow'}}">他的关注</router-link>
 <router-link exact to="?info=share">他的分享</router-link>

query后面跟的是一个对象,内容是查询字符串的键值,
path里面为空,不能是'/','/'表示根路径

九、给导航切换增加过度动画transition

过渡的css类名:
v-enter:定义进入过渡的开始状态
v-enter-active:定义进入活动状态
v-enter-to:定义进入的结束状态
v-leave:定义离开过渡的开始状态
v-leave-active:定义离开活动状态
v-leave-to:定义离开的结束状态
vue-router教程

自定义过度动画:
.left-enter{
    tranform:translateX(-100%)
}
.left-enter-to{
    tranform:translateX(0)
}
.left-enter-active{
    transition:1s;
}
使用:
<transition name="left" mode="out-in">
    <router-view class="center"></router-view>
</transition>

过渡模式:
可能会有2个组件同时出现在页面上的情况,会重叠在一起,很难看。这里就用到了过渡模式

  • in-out:新元素先进行过渡,完成之后当前元素过渡离开
  • out-in:当前元素先进行过渡,完成之后新元素过渡进入
<transition mode="out-in">
    <router-view class="center"></router-view>
</transition>

路由元信息:
在路由配置中meta可以配置一些自定义数据,用在路由信息对象中
访问meta中数据:$route.meta.index //index是自己设置的属性名

<template>
  <div id="app">
        <div class="nav-box">
            <ul class="nav">
                <router-link :to="idx" tag="li" event="mouseover">
                    <i class="fa fa-home"></i>
                    <span>home</span>
                </router-link>

                <li>
                    <router-link :to="{path:'/about'}" event="mouseover">about</router-link>
                </li>
                <li>
                    <router-link to="/document" event="mouseover">document</router-link>
                </li>
                <li>
                    <router-link to="/user" event="mouseover">user</router-link>
                </li>
            </ul>
        </div>
        <router-view name="slider" class="" />
    <!--<transition mode="out-in">
            <router-view class="center"></router-view>
        </transition>-->
        <transition :name="names">
            <router-view class="center"></router-view>
        </transition>
  </div>
</template>

<script>
export default {
  name: 'App',
  data(){
    return{
        idx:'/home',
        names:"left"
    }
  },
  watch:{
    $route(to,from){
        console.log(to.meta.index)  //目标导航下标
            console.log(from.meta.index)  //离开导航下标
        if(to.meta.index < from.meta.index){
            this.names="left"
        }else{
            this.names="right"
        }
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.v-enter{
    opacity: 0;
}
.v-enter-to{
    opacity: 1;
}
.v-enter-active{
    transition: 0.5s;
}
.v-leave{
    opacity: 1;
}
.v-leave-to{
    opacity: 0;
}
.v-leave-active{
    transition: 0.5s;
}

.left-enter{
    transform: translateX(-100%);
}
.left-enter-to{
    transform: translateX(0);
}
.left-enter-active,.right-enter-active{
    transition: 1s;
}

.right-enter{
    transform: translateX(100%);
}
.right-enter-to{
    transform: translateX(0);
}

index.js配置:
{
    path: '/home',
    name: 'Home',
    component: home,
    meta:{  //自定义一些属性
        index:0
    }
},

</style>

十:编程式导航
☆ 借助于router的实例方法$router,通过编写代码来实现导航的切换,router-link是标签进行导航,这里是通过js代码

  • $route为当前router跳转对象,里面可以获取name、path、query、params等
  • $router为VueRouter实例,想要导航到不同URL,则使用$router.push方法

  • back:回退一步 //this.$router.back();
  • forward:前进一步,这两种都只能前进或者后退一步 //this.$router.forward();
  • go:指定前进回退步数 //this.$router.go(-2);如果为0,则是刷新当前页面
  • push:导航到不同url,向history栈添加一个新的记录,用的比较多
    this.$router.push('/document');或下面的用法:
    this.$router.push({ path:'/document',query:{info:'follow'} });
  • replace:导航到不同url,替换history栈中当前记录

十一:导航钩子函数
导航发生变化时,导航钩子主要用来拦截导航,让它完成跳转或者取消

  1. 执行钩子函数位置:
    router全局
    单个路由
    组件中
  2. 钩子函数:
    router实例上(全局钩子函数,所有导航通用):beforeEach、afterEach
    单个路由中(只在访问定义beforeEnter的那个组件导航上才会触发):beforeEnter
    组件内的钩子:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
  3. 钩子函数接收的参数:
    to:要进入的目标路有对象,到哪里去
    from:正要离开导航的路有对象,从哪里来
    next:用来决定跳转或取消导航,只有执行改函数才会渲染要进入的组件

案例1:定义全局钩子函数,只要有导航切换的地方就会触发,写在index.js路由配置文件下
let router = new VueRouter({})

//进入路由前
router.beforeEach( ( to,from,next )=>{  
    if( to.meta.login ){  //要进入的组件需要先进行登录
        console.log(to);
        next('/login');  //如果没有登录就重定向到登录页
    }else{
        next();  //已经登录,就渲染要进入的组件内容
    }
} )

//进入路由后
router.afterEach( ( to,from )=>{  //这里不需要next了,因为已经进入了
    if( to.meta.title ){  //切换不同的组件,页面title改变为对应的值
        window.document.title=to.meta.title;
    }else{
        window.document.title='myTitle';  //注意这里document前面需要加上window,否则访问不到
    }
} )

index.js
{
    path:'home',
    component:'home',
    meta:{
        index:1,
        login:true,
        title:'home'
    }
}

案例2:定义单个路由钩子函数,只在进入该路由导航时才执行该钩子函数,写在路由配置里

{
    path:'/document',
    conponent:'document',
    beforeEnter(to,from,next){
        next();  //执行了这个才会渲染组件
    }

}

案例3:定义组件内的钩子函数,进入该组件时执行该钩子函数,写在组件内
比如:about.vue组件

<script>
export default({
    data(){
        msg:'改变前',
        beforeCreate(){
            console.log('beforeCreate');
        },
        beforeRouteEnter( to,from,next ){  //进入的导航钩子,决定是否进入这个导航
            //next();  //执行了这个才会渲染组件
            console.log(this);  //this是undefined,所以不能通过this.msg获取data,可以通过next的回调函数
            //路由的钩子函数先执行,组件的钩子函数后执行,此时,组件的实例还没有创建,所以this是undefined
            next( (vm)=>{
                vm.msg='改变了';
            } )
        },
        beforeRouteUpdate( to,from,next ){  //点击二级导航,决定是否进入到二级导航里面
            //next  //写了才会更新
        },
        beforeRouteLeave( to,from,next ){
            //next();  //写了这个,才会从当前导航离开,否则会一直停留在当前导航页
        }
        //【注意】,这里面的路由钩子函数都是写在单个组件内的,局部的
    }
})
</script>

十二、vue-cli项目实战
1、多个组件,将每个组件所需要的样式,抽离出来,放在assets/css/文件夹下面(assets文件夹放资源文件:css/js/img),
建立css入口文件app.css
然后在其中import引入全部的组件样式文件
然后在main.js里面,import这个app.css文件,// import './assets/css/app.css'
即可在项目中引入全部css文件( webpack会帮助引入 )
2、components文件夹放公共组件,即每个页面都会用到的部分,如导航栏
views文件夹放每个页面独立的组件
3、libs:公共库,自己封装的js或者第三方工具库放在这里面
怎么使用自定义的库呢:
单页面使用:单页面引入,然后直接使用里面的方法
import local from '@/lib/utils'
local.fetch、local.save
全局使用:作为Vue的插件
举例:对象obj作为Vue的插件,key值必须为install,对应的是一个函数
let obj = {
install:function( Vue,options ){
Vue.prototype.$abc = '自定义属性'; //其他页面通过this.$abc获取到'自定义属性'值
console.log(Vue); //构造函数
console.log(options); //{a:1}
}
}
Vue.use( obj , {a:1} );

首先在main.js引入:import Utile from './lib/utils'
然后注册到Vue实例:Vue.use( Utile )
最后:就可以在每个组件,通过this访问到$local对象,对象上面有save和fetch两个方法

如果在组件内部获取不到this,可以通过router.app.$local来获取$local对象

4、在判断是否需要登录时,如果父子路由都需要检测meta里面是否都有需要登录的情况时,to代表的是当前进入路由的信息对象,下面有一个属性:matched,是一个数组,里面存了当前的路由信息对象以及父路由信息对象
vue-router教程

十三、项目知识点集结
1、$refs的用法
<input type="text" class="input1" ref="input1"/>
一般来讲,获取DOM元素,需document.querySelector(".input1").value获取这个dom节点的值
用ref绑定之后,this.$refs.input1.value 就可以
2、
vue-router教程

router.beforeEach( ( to,from,next )=>{  
    if( to.meta.login ){ 
        console.log(to);  //这个是要进入的路由信息对象
    }
}
to对象里面有一个:matched数组Array[2],包含当前路由所有嵌套路径片段的路由信息,包括自己的信息和父路由的信息

3、some()方法
Array.some(function( item ){})

  • 用于检测数组中的元素是否满足指定条件(函数提供),会依次执行数组的每个元素
  • 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测
  • 如果没有满足条件的元素,则返回false
  • 如果return返回值有一项为true,那么结果就是true

4、导航钩子函数,主要是用在进行导航是否跳转或者拦截的一些操作,比如点击导航,用户是否需要登录才能跳转还是说可以直接进行跳转
有三个地方可以写导航钩子函数
全局、单个路由、单个组件中

5、开发环境页面完成之后,使用命令:npm run build打包项目,生成dist文件夹上线
默认是把dist文件夹下面的所有文件放在服务器的根目录下
但是,如果不是放在根目录下,而是服务器的二级目录下,那么就得配置config/index.js文件,里面的assetsPublicPath属性,改为二级目录名称即可

6、页面上线之后,打开页面,然后刷新会出现404,需要配置apache里的httpd.conf文件
删除...前面的#号,释放该模块...具体看视频,只要是404,都重定向到index.html

7、$router和$route的区别
this.$router:router为VueRouter的实例,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。。。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。。。
vue-router教程
this.$route: 表示当前正在用于跳转的路由器对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name、path、query、params等方法;
vue-router教程

8、

to:要进入的目标路有对象,到哪里去
from:正要离开导航的路有对象,从哪里来
savePosition:记录滚动条的坐标位置 只在点击前进后退按钮时才有记录
next:用来决定跳转或取消导航,只有执行改函数才会渲染要进入的组件

$route(to,from){}
scrollBehavior(to,from,savePosition){}
beforeRouteEnter( to,from,next ){}

9、在任何一个路由里面,可以通过this.$route获取到如下信息:
vue-router教程

在任何一个路由钩子函数里面,通过to参数,可以获取到如下信息:
vue-router教程
其实二者一模一样;
在router/index.js里面,可以直接通过router获取到路由信息

转自:https://blog.51cto.com/9161018/2326924