Vue2从入门到出门(续)

686 阅读4分钟

接[Vue2从入门到出门](Vue2从入门到出门 - 掘金 (juejin.cn)),实在放不下了兄弟萌。

路由

了解路由之前,我们先了解一下单页应用:

单页应用(SPA)

SPA(Single Page web Application),指只有一个主页面的应用,浏览器一开始会加载必须的HTML,CSS和JavaScript,所有的操作都在这张页面上完成。

优点:

  • 用户操作体验好,用户不用刷新页面,整个交互通过Ajax操作进行
  • 前后端分离清晰,前端通过HTTP请求获取数据

缺点:

  • 首页加载慢,会将页面所需内容打包统一加载
  • 对SEO不友好,所有内容都在一个页面上动态替换展示

SEO

SEO(Search Engine Optimization)搜索引擎优化:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名,以获得收益的方法。

前端路由可以帮助我们在仅有一个页面的情况下,为SPA中的各个视图匹配一个唯一标识。

常规

<div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <router-link to="/mine">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>Hello {{name}}</div>`,
            data(){
                return{
                    name:'WDY'
                }
            }
        })
        Vue.component('mine',mine)
​
        const router = new VueRouter({
            routes:[
                {path:'/',component:home},
                {path:'/mine',component:mine}
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220709151043673.png

image-20220709151106135.png

多级路由

<div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <router-link to="/mine">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link to='/mine/me'>me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
            </div>`,
            data(){
                return{
                    name:'WDY'
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由me</div>`,
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {path:'/',component:home},
                {
                    path:'/mine',
                    component:mine,
                    children:[
                        {
                            path:'me',
                            component:me
                        },
                        {
                            path:'mee',
                            component:mee
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

第一层: image-20220709152728912.png

image-20220709152741455.png 第二层: image-20220709152759765.png

image-20220709152811857.png

命名路由

给路由起一个别名,即用别名替代路径也可正常使用:

<div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <!-- <router-link to="/mine">Go to Mine</router-link> -->
            <router-link :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link to='/mine/me'>me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
            </div>`,
            data(){
                return{
                    name:'WDY'
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由me</div>`,
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {path:'/',component:home},
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            path:'me',
                            component:me
                        },
                        {
                            path:'mee',
                            component:mee,
                            name:'wo'
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220709160410094.png

重定向

当我们输入一个网址时,它会被指向我们所重定向的那个网址:

<div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <!-- <router-link to="/mine">Go to Mine</router-link> -->
            <router-link :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link to='/mine/me'>me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
            </div>`,
            data(){
                return{
                    name:'WDY'
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由me</div>`,
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/',
                    redirect:'/mine'
                },
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            path:'me',
                            component:me
                        },
                        {
                            path:'mee',
                            component:mee,
                            name:'wo'
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

输入:

image-20220709163328547.png敲回车,会跳转到我们设置的mine页面:image-20220709163359605.png

数据传输

query

栗子使用了query进行数据传递,同时也使用了命名路由的语法:

  • 传递后会形成新的路径
<div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <!-- <router-link to="/mine">Go to Mine</router-link> -->
            <router-link :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
            </div>`,
            data(){
                return{
                    name:'WDY'
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由{{$route.query.name}}</div>`,
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/',
                    redirect:'/mine'
                },
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            path:'me',
                            component:me,
                            name:'wo'
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220709173436785.png

params

栗子使用了params进行数据传递,同时也使用了命名路由的语法:

  • 传递后会形成新的路径
<div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <!-- <router-link to="/mine">Go to Mine</router-link> -->
            <router-link :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',params:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由{{$route.params.name}}--{{$route.params.age}}</div>`,
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/',
                    redirect:'/mine'
                },
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me/:name/:age',
                            component:me
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220709175242468.png

动态路由

query与params进行数据传递又称为动态路由,注意区分两者路由格式的配置

props

   <div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <!-- <router-link to="/mine">Go to Mine</router-link> -->
            <router-link :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby']
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/',
                    redirect:'/mine'
                },
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                            }
                        
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220709180056016.png

方法二:

以true和false设定props,当为true时,可以传递,当为false时,不会传递。该方式使用params传参。

<div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <!-- <router-link to="/mine">Go to Mine</router-link> -->
            <router-link :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',params:{name:name,age,hobby}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                    hobby:'eat'
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby']
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/',
                    redirect:'/mine'
                },
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me/:name/:age/:eat',
                            component:me,
                            props:true
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

编程式路由导航

借助router-link实现记录替换(replace):不加replace默认为push

 <div id="app">
        <p>
            <router-link replace to="/">Go to Home</router-link>
            <router-link replace :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
                <button @click='forward'>前进</button>
                <button @click='back'>后退</button>
                <button @click='go'>go</button>
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                }
            },
            methods:{
                forward(){
                    this.$router.forward()
                },
                back(){
                    this.$router.back()
                },
                go(){
                    this.$router.go(2)
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby']
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                              
                            }
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

不借助router-link实现路由跳转:

常用作用
forward前进
back后退
go(参数)前进多少或后退多少
push追加历史记录
replace替换当前记录
    <div id="app">
        <p>
            <router-link to="/">Go to Home</router-link>
            <!-- <router-link to="/mine">Go to Mine</router-link> -->
            <router-link :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <router-view></router-view>
                <button @click='forward'>前进</button>
                <button @click='back'>后退</button>
                <button @click='go'>go</button>
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                }
            },
            methods:{
                forward(){
                    this.$router.forward()
                },
                back(){
                    this.$router.back()
                },
                go(){
                    this.$router.go(2)
                }
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby']
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                              
                            }
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220709183151721.png

缓存路由(keep-alive)

包裹动态组件时,会缓存不活动的组价实例,而不是销毁它们。可以用来缓存组件,避免多次加载相同的组件,减少性能消耗,提高用户体验。

属性作用
include字符串或正则表达式,只有名称匹配的组件会被缓存
exclude字符串或正则表达式,任何名称匹配的组件都不会被缓存
max最多可以缓存多少组件实例

使用keep-alive缓存路由时,一定给组件命名:

<div id="app">
        <p>
            <router-link  to="/">Go to Home</router-link>
            <router-link  :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <keep-alive include='me'>
                    <router-view></router-view>
                </keep-alive>
                
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                }
            },
            methods:{
                
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            name:'me',
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby'],
            beforeDestroy(){
                console.log('me将被销毁')
            },
            destroyed(){
                console.log('me已经被销毁')
            }
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`,
            beforeDestroy(){
                console.log('mee将被销毁')
            },
            destroyed(){
                console.log('mee已将被销毁')
            }
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                            },
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

切换me组件与mee组件:

image-20220710122441942.png

失活与激活

组件当跳入页面就会激活,当跳出页面就会失活

属性作用
activated组件激活
deactivated组件失活
    <div id="app">
        <p>
            <router-link  to="/">Go to Home</router-link>
            <router-link  :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
                <keep-alive include='me'>
                    <router-view></router-view>
                </keep-alive>
                
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                }
            },
            methods:{
                
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            name:'me',
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby'],
            activated(){
                console.log('me组件被激活')
            },
            deactivated(){
                console.log('me组件已经失活')
            },
            beforeDestroy(){
                console.log('me将被销毁')
            },
            destroyed(){
                console.log('me已经被销毁')
            }
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            template:`<div>我是多级路由mee</div>`,
            beforeDestroy(){
                console.log('mee将被销毁')
            },
            destroyed(){
                console.log('mee已将被销毁')
            }
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/home',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                            },
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220710124211728.png

历史记录模式(hash&history)

hash(默认)

URL中#及后面的部分为hash值,它虽然出现在URL中,但不会被包含在HTTP请求中。

history

URL常见的格式/

路由元信息

每个路由携带的信息,可以与守卫搭配使用。

<div id="app">
        <p>
            <router-link  to="/">Go to Home</router-link>
            <router-link  :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            name:'home',
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            name:'mine',
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
​
                <router-view></router-view>
                
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                }
            },
            methods:{
                
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            name:'me',
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby'],
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            name:'mee',
            template:`<div>我是多级路由mee</div>`,
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            mode:'history',
            routes:[
                {
                    path:'/',
                    component:home,
                    meta:{
                        login:true
                    }
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    meta:{
                        login:true
                    },
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                            },
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ],
                }
            ]
        })
​
        router.beforeEach((to,from,next)=>{
            if(to.meta.login == true){
                next()
            }
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220710173753412.png

Go to Home与Go to Mine可以正常转换,而me与mee不能正常显示其信息。

路由守卫

路由跳转过程中的一些钩子函数,在路由跳转时进行一些操作。类似于组件的生命周期钩子。

全局守卫

全局前置守卫(router.beforeEach((to,from,next)=>{}))

初始化时被调用,每次路由切换之前被调用。

属性作用
to即将进入目标的路由
from当前导航将要离开的路由
next函数,决定是否展示页面(可以是判断条件等)
全局解析守卫(router.beforeResolve((to,from,next)=>{}))

组件被解析之后调用。

全局后置守卫(router.afterEach((to,from)=>{}))

初始化时被调用,每次路由切换之后被调用。

属性作用
to即将进入的目标路由
from当前导航要离开的路由
    <div id="app">
        <p>
            <router-link  to="/">Go to Home</router-link>
            <router-link  :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            name:'home',
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            name:'mine',
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
​
                <router-view></router-view>
                
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                }
            },
            methods:{
                
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            name:'me',
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby'],
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            name:'mee',
            template:`<div>我是多级路由mee</div>`,
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                            },
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ]
                }
            ]
        })
​
        router.beforeEach((to,from,next)=>{
            console.log(to)
            console.log(from)
            next()
        })
​
        
        router.afterEach((to,from)=>{
            console.log(to)
            console.log(from)
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220710161308334.png

独享守卫(beforeEnter((to,from,next)=>{}))

与全局守卫用法相同,但是只针对一个页面:

   <div id="app">
        <p>
            <router-link  to="/">Go to Home</router-link>
            <router-link  :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            name:'home',
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            name:'mine',
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
​
                <router-view></router-view>
                
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                }
            },
            methods:{
                
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            name:'me',
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby'],
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            name:'mee',
            template:`<div>我是多级路由mee</div>`,
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                            },
                            beforeEnter:((to,from,next)=>{
                                console.log(to)
                                console.log(from)
                                next()
                            })
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ],
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220710162309694.png

组件内守卫

beforeRouteEnter((to,from,next)=>{})

在组件创建前触发,此时组件还没有创建成功,不能访问this实例

beforeRouteUpdate((to,from,next)=>{})

当前路由改变,但是该组件被复用

beforeRouteLeave((to,from,next)=>{})

离开组件时触发

   <div id="app">
        <p>
            <router-link  to="/">Go to Home</router-link>
            <router-link  :to="{name:'wode'}">Go to Mine</router-link>
        </p>
​
        <router-view></router-view>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const home = Vue.extend({
            name:'home',
            template:`<div>Hello World</div>`,
        })
        Vue.component('home',home)
​
        const mine = Vue.extend({
            name:'mine',
            template:`<div>
                Hello {{name}}
                <ul>
                    <li>
                        <router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>    
                    </li>    
                    <li>
                        <router-link to='/mine/mee'>mee</router-link>
                    </li>
                </ul>
​
                <router-view></router-view>
                
            </div>`,
            data(){
                return{
                    name:'WDY',
                    age:100000,
                }
            },
            methods:{
                
            }
        })
        Vue.component('mine',mine)
​
        const me = Vue.extend({
            name:'me',
            template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
            props:['name','age','hobby'],
            beforeRouteEnter(to,from,next){
                console.log(to)
                console.log(from)
                next()
            },
            beforeRouteLeave(to,from,next){
                console.log('-----------------leave')
                console.log(to)
                console.log(from)
                next()
            }
        })
        Vue.component('me',me)
​
        const mee = Vue.extend({
            name:'mee',
            template:`<div>我是多级路由mee</div>`,
        })
        Vue.component('mee',mee)
​
        const router = new VueRouter({
            routes:[
                {
                    path:'/',
                    component:home
                },
                {
                    path:'/mine',
                    name:'wode',
                    component:mine,
                    children:[
                        {
                            name:'wo',
                            path:'me',
                            component:me,
                            props($route){
                                return{
                                    name:$route.query.name,
                                    age:$route.query.age,
                                    hobby:'eat'
                                }
                            },
                        },
                        {
                            path:'mee',
                            component:mee,
                        }
                    ],
                }
            ]
        })
​
        const app = new Vue({
            el:'#app',
            router:router,
        })  
    </script>

image-20220710164939547.png

Vue脚手架

安装(npm版)

Vue CLI 4.x 需要 Node.js v8.9 或更高版本 (推荐 v10 以上)。你可以使用 nnvmnvm-windows 在同一台电脑中管理多个 Node 版本

  • npm install -g @vue/cliimage-20220706164116469.png
  • 创建项目,选择版本

image-20220706164613359.png

到这儿一个简单的脚手架就安装好了:image-20220706164727225

文件存放
node_modulesnode安装依赖包,即npm或yarn安装东西的仓库
pubic存放静态资源
src资源文件夹,存放项目代码的文件夹
.gitignoregit上传文件时,不上传的文件写在此处
babel.config.js配置文件,用于兼容更多浏览器
jsconfig.json指定根文件和JavaScript语言服务提供的功能选项
package.json项目基本信息
package-lock.json锁定安装的版本上传到git
README.md描述,说明性文件
vue.config.js可选配置文件
src下文件存放
asset静态资源
components公共组件存放
router路由
App.vue主组件
main.js项目核心文件,实例,应用的插件等

Vuex

Vuex是Vue的状态管理模式,可以将其理解为一个容器,里面存放着应用中的大部分状态(state)。

image-20220710191820324.png

概念作用
State存储所有共享的状态信息
Getters对数据进行一些处理
Mutations对数据进行操作
Actions包含异步操作
Modules分模块管理数据

下面是一个简单的栗子:

    <div id="app">
        {{$store.state.sum}}
        <button @click="add">+</button>
        <button @click="actionsAdd">actions+</button>
    </div>
​
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
​
        const store = new Vuex.Store({
            state:{
                sum:0
            },
            actions:{
                actionsAdd(context,value){
                    context.commit('add',value)
                }
            },
            mutations:{
                add(state,value){
                    state.sum += value
                }
            }
        })
​
        const app = new Vue({
            el:'#app',
            store:store,
            data:{
                num:1
            },
            methods:{
                add(){
                    this.$store.commit('add',this.num)
                },
                actionsAdd(){
                    this.$store.dispatch('actionsAdd',this.num)
                }
            }
        })  
    </script>

image-20220710192516738.png

两个按钮均可实现加一

拓展

响应式原理

创建Vue实例时,Vue会遍历data中的属性(即已经存在的属性),之后用Object.defineProperty将这些property转化为getter/setter,并在内部让Vue能追踪依赖,在property被访问和修改时通知变更。每个实例都有一个watcher实例,他会在属性渲染的过程中把property记录为依赖,之后当setter触发时,会通知watcher,从而使它相关联的组件重新渲染。

image-20220711095612792.png

单向数据流

Vue提倡单向数据流,即数据总是从父组件流向子组件,子组件不能对父组件传来的数据进行修改,只能通过请求的方式让父组件对数据进行修改($emit)从而达到更新数据的目的。