1. 程式人生 > 實用技巧 >vue 過濾器 鉤子函式 路由 全家桶

vue 過濾器 鉤子函式 路由 全家桶

Vue過濾器、鉤子函式、路由、全家桶等

本節目錄

一 Vue的過濾器

  1 moment.js

    在這裡我們先介紹一個moment.js的js前端時間處理的控制元件

      

      

    點選下載之後,我們把檔案內容copy下來,在我們自己的專案本地目錄建立一個叫做moment.js的檔案,將內容儲存到裡面,通過script的src屬性來引入

      

    

    這個moment.js提供了很多的方法

    日期格式化:

moment().format('MMMM Do YYYY, h:mm:ss a'); // 四月 2日 2019, 8:05:29 晚上
moment().format('dddd');                    // 星期二
moment().format("MMM Do YY");               // 4月 2日 19
moment().format('YYYY [escaped] YYYY');     // 2019 escaped 2019
moment().format();                          // 2019-04-02T20:05:29+08:00

    相對時間

moment("20111031", "YYYYMMDD").fromNow(); // 7 年前
moment("20120620", "YYYYMMDD").fromNow(); // 7 年前
moment().startOf('day').fromNow();        // 20 小時前
moment().endOf('day').fromNow();          // 4 小時內
moment().startOf('hour').fromNow();       // 6 分鐘前

    日曆時間

moment().subtract(10, 'days').calendar(); // 2019年3月23日
moment().subtract(6, 'days').calendar();  // 上週三晚上8點06
moment().subtract(3, 'days').calendar();  // 上週六晚上8點06
moment().subtract(1, 'days').calendar();  // 昨天晚上8點06分
moment().calendar();                      // 今天晚上8點06分
moment().add(1, 'days').calendar();       // 明天晚上8點06分
moment().add(3, 'days').calendar();       // 本週五晚上8點06
moment().add(10, 'days').calendar();      // 2019年4月12日

  後面我們的程式碼中會用到這個moment.js的功能。

  2 區域性過濾器

    在當前元件內容使用過濾器,給某些元素添油加醋,看程式碼

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

<div id="app">
    <App></App>

</div>


<script src="vue.js"></script>
<script src="moment.js"></script>
<script src="../jquery.js"></script>
<script>

    let App={
        data(){
            return{
                msg:'hello world',
                time:new Date(),
            }
        },
        template:
            //模板語法中使用過濾器{{ 資料|filters裡面定義的函式名 }}
            `
            <div>
                我是一個App元件{{ msg | myReserve }}  
                <h2>{{ time | myTime('YYYY-MM-DD') }}</h2>  還可以傳多個引數,呼叫方法的時候myTime(v1,v2,v3)
            </div>
        `,
        //定義區域性過濾器
        filters:{
            //val引數就是傳送過來的資料
            myReserve:function (val) {
                console.log(val);
                //對資料過濾完之後,需要return
                return val.split('').reverse().join('')
            },
            //看h2標籤裡面怎麼使用的,看傳參方式。
            myTime:function (val,formatStr) {
                // return moment(val).format('YYYY-MM-DD') ;//通過我們引用的moment.js外掛來出來日期格式顯示,現在這是顯示年-月-日的形式,其實這個日期格式是後端傳給你的,讓你生成什麼格式的,你就生成什麼格式的,所以我們把格式也做一個動態的
                return moment(val).format(formatStr) //年-月-日的形式,其實這個日期格式是後端傳給你的,讓你生成什麼格式的,你就生成什麼格式的,所以我們把格式也做一個動態的
            }
        }
    };

    new Vue({
        el:'#app',
        data(){
            return{

            }
        },
        components:{
            App,
        }

    })

</script>
</body>
</html>

  3.全域性過濾器

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

<div id="app">
    <App></App>

</div>


<script src="vue.js"></script>
<script src="moment.js"></script>
<script src="../jquery.js"></script>
<script>
    //全域性過濾器,可以定義多個,看寫法
    Vue.filter('myTime',function (val,formatStr) {
       return moment(val).format(formatStr)
    });
    // vue.filter('myTime2',function (val,formatStr) {
    //    return moment(val).format(formatStr)
    // });

    let App={
        data(){
            return{
                msg:'hello world',
                time:new Date(),
            }
        },
        template:
            `
            <div>
                我是一個App元件{{ msg | myReserve }}
                <h2>{{ time | myTime('YYYY-MM-DD') }}</h2>
            </div>
        `,
        //定義區域性過濾器
        filters:{
            myReserve:function (val) {
                console.log(val);
                return val.split('').reverse().join('')
            },
            // //看h2標籤裡面怎麼使用的,看傳參方式。並且你想,現在這個日期格式化寫到了一個元件裡面,其他元件是不是沒法用啊,所以我們想把它搞成一個全域性的,看上面全域性過濾器的寫法
            // myTime:function (val,formatStr) {
            //     return moment(val).format(formatStr)
            // }
        }
    };

    new Vue({
        el:'#app',
        data(){
            return{

            }
        },
        components:{
            App,
        }

    })

</script>
</body>
</html>

  簡單總結:

    區域性過濾器

宣告:
filters:{
    '過濾器的名字':function(val,a,...){
        //a 假如是chao,而val是當前的資料
    }
    
}    
使用:
{{ 資料 | 過濾器的名字('chao','xxx') }}

    全域性過濾器(所有元件都能用)

宣告
    Vue.filter('過濾器的名字',function(val,a,...){
        //a:chao,val:資料
    })
使用
    {{ 資料 | 過濾器的名字('chao','xxx') }}

二 生命週期的鉤子函式

  從生到死的過程中有一些能夠搞事情的鉤子,就是我們說的鉤子函式,和django裡面的那些鉤子理解起來是一樣的。

  看官網怎麼說的,下圖展示了例項的生命週期。你不需要立馬弄明白所有的東西,不過隨著你的不斷學習和使用,它的參考價值會越來越高。

    

  然後生命週期的鉤子函式在官網的這個地方看:

    

    

  我們來看一下這些鉤子函式:

    

  鉤子函式的執行順序簡單驗證,看程式碼:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    {{ data }}

</div>

<script src="vue.js"></script>
<script>
    var vm=new Vue({
        el:"#app",
        data:{
            data:"chao",
            info:"Jaden"
        },
        //元件建立完成之前可以做一些事情,有些場景比如說某個頁面或者app開啟的時候,點選打開了但是還沒執行起來的時候你看到有些動畫效果,有個小孩划船啊什麼的,等一會軟體開啟之後,這個效果就沒有了
        beforeCreate:function(){
            console.log("建立前========");
            console.log(this.data);  //undefined
            console.log(this.$el);   //undefined,這是我們要將資料掛載到的上面的id為app的div標籤物件
        },
        //元件建立完成之後,但是dom中的資料還沒掛載上的之前,也就是div標籤還沒有被vue物件獲取到的時候,那麼div標籤中的資料{{ data }}還沒有傳入資料
        created:function(){ ///*****重點
            //一般在這個鉤子函式裡面傳送ajax請求,去後臺請求資料,並賦值給我們的data裡面的資料屬性,因為在上一步beforeCreate裡面傳送ajax是沒有什麼用的,因為資料屬性你還沒有拿到,this.data還沒資料
            console.log("已建立========");
            console.log(this.info);//Jaden
            console.log(this.$el); //undefined,還沒有獲得DOM,$el屬性還不存在
        },
        //掛載之前,意思是找到了id為app的div標籤(dom),但是資料還沒有掛載進去的時候觸發的函式
        beforeMount:function(){
            console.log("mount之前========");
            console.log(this.info); //Jaden
            console.log(this.$el); //拿到了標籤物件<div id="app">{{ data }}</div>,但是data還沒資料,現在這個dom是個虛擬dom,只是個叫法,是react提出來的,用到的是一個diff演算法來搞的,每個dom操作的效能高了零點幾毫秒,v-for中的key的使用也是diff演算法的其中一個用法,瞭解一下就行了
        },
        mounted:function(){ //*****重點
            console.log("mounted========");
            console.log(this.info);//Jaden
            console.log(this.$el);//拿到了標籤物件<div id="app">Jaden</div>,並且{{ data }}已經掛載上資料了
            //說明這個方法之後,真實的dom已經生成了,我們就可以在這個方法裡面通過js來操作dom搞事情了,但是vue的設計裡面說一般都用資料驅動來完成你的需求,很少用dom操作,除了一些特殊情況。
        },
        //更新資料屬性的操作觸發了,但是還沒有完成資料更改的時候,比如vm.data = 'xxx';操作
        beforeUpdate:function(){
            //應用,獲取原始的dom搞些事情
            console.log("更新前========");

        },
        //資料更改完成之後觸發
        updated:function(){
            //應用:獲取更新之後的dom搞事情
            console.log("更新完成========");
        },
        //vue物件或者元件銷燬操作觸發,但是還沒有完成銷燬的時候觸發的函式,用v-if可以讓元件銷燬,或者用vue物件(vm).destory()方法來銷燬vue物件的方式來演示這個效果:vm.$destroy();
        beforeDestroy:function(){
            console.log("銷燬前========");
            console.log(this.info);//Jaden
            console.log(this.$el);//<div id="app">xxx</div>
        },
        //元件或者vue物件銷燬之後觸發的事情,用的也挺多的,一般用在定時器的銷燬上,因為即便是我們通過上面的v-if來銷燬元件,但是你的元件裡面如果有定時器,這個定時器是不會銷燬的,需要我們手動銷燬,如果這個定時器裡面是播放動畫等內容,會消耗你的頁面效能。
        destroyed:function(){
            console.log("已銷燬========");
            console.log(this.info);//Jaden
            console.log(this.$el);//<div id="app">xxx</div>
        }
    })

</script>

</body>
</html>

    看效果:

      

    簡單總結: 

      1、beforeCreate 此時$el、data 的值都為undefined

      2、建立之後,此時可以拿到data的值,但是$el依舊為undefined

      3、mount之前,$el的值為“虛擬”的元素節點

      4、mount之後,mounted之前,“虛擬”的dom節點被真實的dom節點替換,並將其插入到dom樹中,於是在觸發mounted時,可以獲取到$el為真實的dom元素()

        myVue.$el===document.getElementById("app-8") // true

  

  我們來做一個簡單的應用,一個父子元件巢狀的使用:其中還有使用了上面我們沒有寫的兩個鉤子函式activated和deactivated,看看怎麼玩的: 

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="app">
    <App/>
</div>
<script src="vue.js"></script>

<script>
    let Test = {
        data() {
            return {
                msg: 'chao',
                count:0,
                timer:null  //用來記錄定時器的
            }
        },
        template: `
               <div id="test">
                    <div id="box">{{ msg }}</div>
                    <p>{{ count }}</p>
                    <button @click = 'change'>修改</button>
               </div>
            `,
        methods: {
            change() {
                this.msg = 'Jaden';
                //原生js獲取dom的操作,如果document.getElementById('#box');不好用,你就可以用下面這個方法來獲取dom
                document.querySelector('#box').style.color = 'red';
            }
        },
        beforeCreate() {
            console.log('元件建立之前', this.msg);

        },
        created() {
            //動態的修改count的值,並且注意這個定時器會一直觸發下面的beforeUpdate和updated方法
            //因為定時器是不會跟著元件的銷燬而銷燬的,所以我們需要在元件銷燬後手動的銷燬它
           // this.timer = setInterval(()=>{
           //     this.count++
           //     //這裡面可以做一些複雜的動畫效果之類的
           // },1000);

            console.log('元件建立之後', this.msg);
            // this.msg = '嘿嘿黑';

        },
        beforeMount() {
            console.log(document.getElementById('app'));
        },
        mounted() {
            console.log(document.getElementById('app'));
        },
        beforeUpdate() {
            console.log('>>>>>',document.getElementById('app').innerHTML);
        },
        updated() {
            console.log(document.getElementById('app').innerHTML);
        },
        beforeDestroy() {
            console.log('beforeDestroy');
        },
        destroyed() {
            //注意: 定時器的銷燬 要在此方法中處理
            console.log('destroyed',this.timer);
            clearInterval(this.timer);

        },

        //如果使用者頻繁的點選建立和銷燬dom,那麼有損頁面的效能,所以vue又提供了下面的兩個方法
        //啟用,這個方法和下面那個方法需要藉助vue提供的一個內建元件來完成搞事情,看下面的template裡面寫的內容
        activated(){
            console.log('元件被激活了');
        },
        //停止啟用,也就是停用
        deactivated(){
            console.log('元件被停用了');
        }
    };
    let App = {
        data() {
            return {
                isShow:true
            }
        },
        template: //通過v-if就能控制組件的銷燬和建立,來演示對應的Test元件中定義的beforeDestroy和destroyed的方法
            // `
            //    <div>
            //         <Test  v-if="isShow"/>
            //         <button @click = 'clickHandler'>改變test元件的生死</button>
            //    </div>
            // `;
        //啟用和停用鉤子函式,需要藉助vue提供的內建元件<keep-alive> 元件 </keep-alive>,那麼<keep-alive>裡面的元件就會被快取起來,並且元件的狀態也被儲存下來了,即便是點選了消失按鈕,元件也並沒有消失,下次點選顯示的時候,直接從快取裡面將這個元件拿過來用,並且還帶著之前元件的狀態,就減少了dom操作,提高了效能,如果沒有通過這個內建元件來包裹,那麼下面這個場景,使用者點選銷燬和建立的時候,還是觸發的上面的銷燬方法和建立方法,不會執行啟用或者停用的方法,這些方法根據業務的需求來用,沒有絕對的好壞之分。
            `
               <div>
                   <keep-alive>
                     <Test  v-if="isShow"/>  //將它動態的刪除或者新增,就是一個銷燬元件和建立元件的操作,也會觸發Test元件裡面對應的建立銷燬的鉤子函式
                  </keep-alive>
                    <button @click = 'clickHandler'>改變test元件的生死</button>
               </div>
            `,
        methods:{
          clickHandler(){
              this.isShow = !this.isShow;
          }
        },
        components: {
            Test
        },


    };
    new Vue({
        el: '#app',
        data() {
            return {}
        },
        components: {
            App
        }

    })

</script>
</body>
</html>

    在使用activated和deactivated兩個鉤子函式的時候,別忘了配合vue的內建元件<keep-alive>元件</keep-alive>。

  看一個建立和銷燬元件的業務場景:

    

  

  對了,注意一點:django中也是有模板語法的是對不對,上大括號{{}},這和vue的模板語法是衝突的,如果你想在django的模板中使用vue的模板語法,記得要關掉django的{{}}模板語法。

  

三 vue的全家桶

vue全家桶:vue + vue-router + vuex

vue就是我們前面學習的vue基礎,vue + vue-router 主要用來做SPA(Single Page Application),單頁面應用

為什麼要使用單頁面應用呢?因為傳統的路由跳轉,如果後端資源過多,會導致頁面出現'白屏現象',所以我們希望讓前端來做路由,在某個生命週期的鉤子函式中,傳送ajax來請求資料,進行資料驅動,之前比如我們用django的MTV模式,我們是將後端的資料全部渲染給了模板,然後模板再發送給前端進行瀏覽器頁面的渲染,一下將所有的資料都給了頁面,而我們現在使用vue,我可以在元件的鉤子函式中傳送對應的ajax請求去獲取對應的資料,而不是褲衩一下子就把資料都放到頁面上了,單頁面應用給我們提供了很多的便利,說起來大家可能沒有什麼切實的體會,來,給大家推薦一個稀土掘金網站,這個網站就是一個單頁面應用,是一個開發者技術社群網站,裡面的資源會有很多,看樣子:

    

  這樣的網站我們通過django是可以來完成頁面的渲染的,模板渲染嘛,但是這個論壇的資料資源有很多,我們通過django的MTV模式是一下子就將資料全部放到頁面裡面了,那麼頁面通過瀏覽器渲染的時候,瀏覽器可能沒有那麼快渲染出來,會出現幾秒鐘的白屏現象,也就是說幾秒鐘之後使用者才看到頁面的內容,這樣體驗起來就不好,為了使用者體驗好,就用到了我們說的單頁面應用,django模板渲染做大型應用的時候,也就是頁面很複雜,資料量很大的頁面的時候,是不太合適的,當然如果你夠nb,你也可以優化,但是一般它比較適合一些頁面資料比較小的應用。

  那麼解釋一下什麼是單頁應用,看下圖:(react、angular也都是做單頁面應用,很多大型的網站像網易雲音樂,豆瓣等都是react寫的單頁面應用)

      

    

  vue + vue-router就是完成單頁面應用的,vue-router(路由)是vue的核心外掛

  1 路由的基本用法

    這個vue-router外掛需要我們自己下載下來使用,看官網:

      

    下面我們來下載一下vue-router,文件地址,下載vue-router的cnd連結地址:https://unpkg.com/vue-router/dist/vue-router.js

    開啟這連結,將裡面的內容copy下來,然後在我們的本地建立一個vue-router.js的檔案,將內容放進去儲存起來,就可以通過引用本地檔案的方式來使用vue-router的功能了,當然也可以直接使用上面這個cdn的地址。

  

    看本地檔案目錄:

    

    下面我們來使用一下:先看一下我們要做的效果:

    

  

    然後我們看一下官網說的使用方法

// 0. 如果使用模組化機制程式設計,匯入Vue和VueRouter,要呼叫 Vue.use(VueRouter)

// 1. 定義 (路由) 元件。
// 下面兩個元件可以從其他檔案 import 進來
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定義路由
// 每個路由應該對映一個元件。 其中"component" 可以是
// 通過 Vue.extend() 建立的元件構造器,
// 或者,只是一個元件配置物件。
// 我們晚點再討論巢狀路由。
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3. 建立 router 例項,然後傳 `routes` 配置
// 你還可以傳別的配置引數, 不過先這麼簡單著吧。
const router = new VueRouter({
  routes // (縮寫) 相當於 routes: routes
})

// 4. 建立和掛載根例項。
// 記得要通過 router 配置引數注入路由,
// 從而讓整個應用都有路由功能
const app = new Vue({
  router
}).$mount('#app')

// 現在,應用已經啟動了!

  圖解一下:

  

    關於Vue.use()

Vue.use()方法

  好,就按照官網說的方法,我們來寫一寫,看程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">



</div>


<!--vue-router是依賴於vue的,所以先引入vue.js-->
<script src="vue.js"></script>
<script src="vue-router.js"></script>

<script>
    //如果以後是模組化程式設計(元件都分到不同的檔案中了,也就是說元件都是區域性生效的),Vue.use(VueRouter);相當於Vue.Proptotype.$VueRouter = VueRouter這句話,當然內部不是這樣實現的,只是簡單舉個例子,通過原型鏈將VueRouter新增到了vue的原型上,也就是掛到了Vue物件的父類上,通過元件的繼承性我們就能知道將來通過this.$VueRouter就能呼叫到它,下面我們還沒有用到模組化開發,所以其實Vue.use(VueRouter)這句話現在可用可不用
    //0. Vue.use(VueRouter);
    // 1.定義路由元件
    const Home={
        data(){
            return{}
        },
        template:`<div>我是首頁</div>`
    };
    const Course={
        data(){
            return{}
        },
        template:`<div>我是免費課程</div>`
    };

    //2.建立路由
    const router = new VueRouter({
        // key:value,如果鍵值相同,簡寫key就行
        //3.定義路由規則
        routes:[  //定義訪問路徑
            {
                path:'/', //首頁
                component:Home, //路由對應的路由元件
            },
            {
                path:'/course', //首頁
                component:Course, //路由對應的路由元件
            },
        ]
    });

    let App = {
        data(){
            return{}
        },
        //5. router-link和router-view是vue-router提供的兩個全域性元件,router-link將來會自動渲染成a標籤,router-link裡面的to屬性將來渲染成a標籤的href屬性。router-view是路由元件的出口,什麼意思呢,意思是說,我們下面點選路徑為'/'或者為'/course'的a標籤的時候,每個路徑對應著我們上面的一個元件,那麼每個元件都要找到一個出口來渲染自己的元件對應的模板內容,那麼就通過<router-view>這個出口進行渲染,也就是<router-view></router-view>會替換成對應元件的內容。注意使用了vue-router後,咱們上面所有配置的路徑,它都會預設給加一個#,舉個例子我們的home頁面的路徑會自動變成'#/',下面預設顯示我們上面配置的router物件裡面的routes這個陣列的第一個path對應的路徑和內容
        template:
            `
            <div>
                <div class="header">
                    <router-link to="/">首頁</router-link>
                    <router-link to="/course">免費課程</router-link>
                </div>
                <router-view></router-view>
            </div>
            `,
    };

    new Vue({
        el:'#app',
        router,//4.給vue根例項來掛載路由物件,相當於router:router,如果你上面的路由起的名字是rou,那麼這裡寫router:rou
        data(){
            return{}
        },
        template:`<App />`,
        components:{
            App
        }



    })

</script>

</body>
</html>

  看程式碼圖解

    

  路由重定向,大家還記得是什麼嗎,訪問一個網址,自動幫我們重定向到了另外一個網址上,我們通過vue-router也可以做:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">



</div>


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

<script>

    const Home={
        data(){
            return{}
        },
        template:`<div>我是首頁</div>`
    };
    const Course={
        data(){
            return{}
        },
        template:`<div>我是免費課程</div>`
    };

    const router = new VueRouter({
        //HTML5 的history模式,去掉那個路由裡面自動加的#,你用我程式碼測試的時候,先不要加下面這個mode
        mode:'history',//但是這個history模式是必須要有服務端的(我們pycharm中自帶伺服器,這裡伺服器的意思就是一個socket服務端,幫你將檔案傳送給瀏覽器去渲染),將來公司的專案中都是這個模式的,因為公司有伺服器啊,nginx什麼的,這個模式下每個路徑就沒有#號了,直觀好看,官網有解釋,大家可以去看看,加#號其實是個hash模式的url
        routes:[
            {
                path:'/', //開啟頁面,預設訪問的就是根路徑,你開啟這個網頁就會發現自動跳轉到了/home路徑下
                // redirect:'/home' //如果沒有做什麼重定向,其實預設顯示
                redirect:'/home' //重定向,
            },
            {
                path:'/home', //首頁
                component:Home, //路由對應的路由元件
            },
            {
                path:'/course', //首頁
                component:Course, //路由對應的路由元件
            },
        ]
    });

    let App = {
        data(){
            return{}
        },
        template:
            `
            <div>
                <div class="header">
                    <router-link to="/home">首頁</router-link>
                    <router-link to="/course">免費課程</router-link>
                </div>
                <router-view></router-view>
            </div>
            `,
    };

    new Vue({
        el:'#app',
        router,
        data(){
            return{}
        },
        template:`<App />`,
        components:{
            App
        }

    })

</script>

</body>
</html>

  上面程式碼中使用mode:'history'的注意問題,看官網解釋

    

      

    看官網的這個地方:

      

  

    好,上面是我們路由的一些基本用法,那麼我們下面學一些比較常用的高階用法。

  2 命名路由

    

    直接看程式碼吧:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">



</div>


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

<script>

    const Home={
        data(){
            return{}
        },
        template:`<div>我是首頁</div>`
    };
    const Course={
        data(){
            return{}
        },
        template:`<div>我是免費課程</div>`
    };

    const router = new VueRouter({
        // mode:'history', //注意,這裡下面程式碼命令路由演示的時候,把這個mode去掉,pycharm內建的這個伺服器,沒有對根路徑進行很好的配置,所以以這種路徑模式來訪問根路徑會出現404錯誤,先去掉吧,以後再說
        routes:[
            {
                path:'/',
                // redirect:'/home',
                redirect:{name:'Home'}, //重定向使用下面名字的方法

            },
            {
                path:'/home', //首頁
                name:'Home', //給路由起個名字,叫做命名路由,注意不叫別名昂,vue裡面的別名不是這麼搞的,下面在<router-link>裡面寫to屬性的時候,我們就使用名字來寫了,:to="{ name:'home' }",注意是單大括號,這樣可以實現將路由動態起來的效果,不再是寫死了<router-link to="/home">首頁</router-link>
                component:Home, //路由對應的路由元件
            },
            {
                path:'/course', //首頁
                name:'Course',
                component:Course, //路由對應的路由元件
            },
        ]
    });

    let App = {
        data(){
            return{}
        },
        template:
            `
            <div>
                <div class="header">
                    <router-link :to="{ name:'Home' }">首頁</router-link>
                    <router-link :to="{ name:'Course' }">免費課程</router-link>
                </div>
                <router-view></router-view>
            </div>
            `,
    };

    new Vue({
        el:'#app',
        router,
        data(){
            return{}
        },
        template:`<App />`,
        components:{
            App
        }

    })

</script>

</body>
</html>

  3 動態路由匹配

  

    

  假如我想動態的顯示使用者資訊,每個使用者有自己的資訊,通過使用者的id來判斷是哪個使用者,並顯示對應使用者的資訊,怎麼玩呢,例如我們通過下面的路由方式來搞:

通過訪問下面不同的路徑
/user/1  載入第一個使用者的資訊
/user/2  第二個使用者的資訊
/user/3  第三個使用者的資訊

  相當於路由動態起來了,每個使用者資訊展示部分的元件大家可以用同一個,只是資料不同

  簡單說幾個路由正規化:

    // 常用路由正規化
    // 1
    // http://127.0.0.1:8000/index/user
    // 2 我們要學的這裡的動態路由指的是這第二種
    // http://127.0.0.1:8000/user/1  //路由後面的1\2\3等等的叫做params引數
    // http://127.0.0.1:8000/user/2
    // 3
    // http://127.0.0.1:8000/user?user_id=1  //這種路由後面的?user_id=1叫做query引數
    // http://127.0.0.1:8000/user?user_id=2

    直接看程式碼吧:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">


</div>

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

<script>
    //Vue.use(VueRouter);
//每個使用者資訊的展示都用這個元件 const User={ data(){ return{ user_id:null, //5. 定義一個數據屬性來接收watch改動的資料 } }, //6. template裡面使用一下這個user_id資料屬性 template:`<div>我是使用者{{ user_id }}</div>`, created(){ // 2. console.log(this.$route);//看列印結果,是個object物件,裡面有很多的屬性{fullPath:..,params:{id:1},query:{}等等內容},其中這個query是路由中有query引數的時候,/user?user_id=1,會拿到1,這個object物件就是當前呼叫這個元件的路由物件資訊,以後想找url裡面的一些資訊,就用這個物件找 console.log(this.$route.params.id); //7.別忘了第一次載入元件的時候,我們要給資料屬性的user_id新增資料 this.user_id = this.$route.params.id; //3. 但是這裡你發現點選了使用者1再點選使用者2,你會發現列印的id還是1,這是為什麼呢,這時候你要細心看官網了,官網是這麼說的,兩個路徑使用相同元件的時候,原來的元件例項會被複用,也就是說原來的元件被快取起來了,點選使用者2的時候,你使用的還是使用者1的元件,狀態還是使用者1的元件狀態,並且元件的生命週期鉤子函式不會再被重新呼叫,也就是說這個created方法不會重新執行了,那怎麼辦呢?需要watch來監聽 }, // 4.監聽$route物件,因為它裡面的id資料會發生變化,我們就監聽這個物件的資料變化來做出響應 watch:{ //$route就是上面說的路由資訊物件 '$route'(to,from){ //to就是到哪裡去,from就是從哪裡來,如果我們從使用者1點選到使用者2,那麼你就會看到to表示使用者2的路由資訊物件,from是使用者1的路由資訊物件 // console.log('>>>',to); //{name: "User", meta: {…}, path: "/user/2", hash: "", query: {…},…} //和我們上面在created方法裡面列印的this.$route是一樣的物件 // console.log(from); //{name: "User", meta: {…}, path: "/user/1", hash: "", query: {…},…} // 我們要的就是to裡面的資料 let user_id = to.params.id; this.user_id = user_id; //更改資料屬性 //其實一般這個id也是後端給你的每條資料的id,通過這個id我們可以傳送ajax請求,去後端獲取對應的資料來進行渲染,這裡我們就不模擬傳送了昂,簡單寫寫,我們去上面定義一個user_id資料屬性來動態儲存這個資料 } } }; const router = new VueRouter({ routes:[ { // path:'/user/1', path:'/user/:id', //1. 寫法,這個id就是在下面<router-link>裡面寫params引數的時候{id:1]裡面的id,兩個名字要對應好 name:'User', component:User, //路由對應的路由元件 }, ] }); let App = { data(){ return{} }, template: ` <div> <div class="header"> <router-link :to="{ name:'User',params:{id:1} }">使用者1</router-link> <router-link :to="{ name:'User',params:{id:2} }">使用者2</router-link> </div> <router-view></router-view> </div> `, }; new Vue({ el:'#app', router, //別忘了它,掛載路由物件 data(){ return{} }, template:`<App />`, components:{ App //別忘了它 } }) </script> </body> </html>

  

  4 程式設計式導航

    

    vue-router給我們的vue添加了兩個內建的屬性:$route和$router,$router指的是VueRouter路由物件,$route指的是路由資訊物件,我們在上面使用過了。這兩個物件都可以通過元件物件來呼叫

  下面我們說一下程式設計式導航和宣告式導航:

  宣告式導航就是我們上面的程式碼中寫的,a標籤和a標籤裡面的url直接就渲染好了等你使用:

<router-link :to="{ name:'User',params:{id:1} }">使用者1</router-link>
<router-link :to="{ name:'User',params:{id:2} }">使用者2</router-link>

  程式設計式導航就是以後我們可以通過任意標籤來進行頁面的跳轉等操作,不是單純的上面的router-link渲染出來的a標籤了。

    看官網的解釋:

        在 Vue 例項內部,你可以通過$router訪問路由例項。因此你可以呼叫this.$router.push

        想要導航到不同的 URL,則使用router.push方法。這個方法會向 history 棧新增一個新的記錄,所以,當用戶點選瀏覽器後退按鈕時,則回到之前的 URL。

        當你點選<router-link>時,這個方法會在內部呼叫,所以說,點選<router-link :to="...">等同於呼叫router.push(...)

      

    使用一下,看程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">

</div>

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

<script>

    const Home={
        data(){
            return{}
        },
        template:`<div>我是首頁</div>`
    };

    const User={
        data(){
            return{
                user_id:null,
            }
        },
        template://點選按鈕跳轉到首頁
                `<div>
                    我是使用者{{ user_id }}
                    <button @click='clickHandler'>跳轉首頁</button>
                  </div>
                `,
        created(){
            this.user_id = this.$route.params.id;
        },
        methods:{
          //程式設計式導航,不是通過router-link渲染的了,而是通過任意的一個標籤(現在用的是button)進行跳轉的,當然通過宣告式router-link也是可以做這個效果的。
            clickHandler(){
                this.$router.push({
                    name:'Home',//通過Home的名字找到Home對應的那個元件進行載入
                })
            }
        },
        watch:{
            '$route'(to,from){
                let user_id = to.params.id;
                this.user_id = user_id;
            }
        }
    };

    const router = new VueRouter({
        routes:[
            {
                path:'/user/:id',
                name:'User',
                component:User,

            },
            {
                path:'/home',
                name:'Home',
                component:Home,

            },

        ]
    });

    let App = {
        data(){
            return{}
        },
        template:
            `
            <div>
                <div class="header">
                    <router-link :to="{ name:'User',params:{id:1} }">使用者1</router-link>
                    <router-link :to="{ name:'User',params:{id:2} }">使用者2</router-link>
                </div>
                <router-view></router-view>
            </div>
            `,
    };

    new Vue({
        el:'#app',
        router,
        data(){
            return{}
        },
        template:`<App />`,
        components:{
            App
        }

    })
</script>

</body>
</html>