[學習vue]全家桶的原理和實現(xiàn)

在正式進入之前先拋出幾個問題:
1 vue-router能不能放在react中使用铅鲤?
2 use vueRouter的時候發(fā)生了什么拐辽?
3 為什么要把router作為一個選項放在new vue 中?
4 為什么router-link router-view 不需要注冊桨吊,就可以直接使用盗胀?
答案就在文章中~~

vue-router

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成车酣,讓構建單頁面應用變得易如反掌。主要解決的問題就單頁面應用的導航問題。

router的任務分析

  • 解析routers選項
  • 監(jiān)控url變化
    html5 history api /login
    hash xx.html#login
//vue-router.js
//聲明插件:vue插件需求實現(xiàn)一個install靜態(tài)方法
let Vue; //保存vue構造函數(shù)引用 目的是不用吧vue打包進去
class KVueRouter{
}
//參數(shù)是vue構造函數(shù)
KVueRouter.install = function(_vue){
    Vue = _Vue;
    //實現(xiàn)一個混入
    Vue.mixin({
          beforeCreate(){
               //獲取KVueRouter實例并掛載到Vue.prototype
               if(this.$options.router){
                  // 在跟組件beforeCreate時執(zhí)行一次且只會執(zhí)行一次
                   Vue.prototype.$router = this.$options.router;
               }
         }
    })
}

這時候有一個疑問湖员,為什么要寫把router掛載的配置寫在混入里贫悄,而不是直接寫在install方法呢?
這是因為和實例的關系很大娘摔,我們先執(zhí)行了Vue.use的方法窄坦,其實是執(zhí)行了插件的install的方法,但是這時候凳寺,實例還不存在呢鸭津,那怎么辦呢,我們只好退而求其次读第,把代碼延后執(zhí)行曙博,延后到當beforeCreate的時候,才執(zhí)行怜瞒。
接下來我們需要注冊兩個全局組件 router-view 和 router-link

...
Vue.component('router-link',{})
Vue.component('router-view',{})

接下來來完成核心任務

class KVueRouter{
         //解析routes
         //監(jiān)聽事件
         //聲明組件
    constructor(options){
          this.$options = options;
          this.routeMap = {};  // {'/index': {component: Index,...}}
          //當前url需要響應式的
          this.app = new Vue({
               data : { current : '/'}
          })
    }

    //初始化
   init(){
      //監(jiān)聽事件
       this.bindEvents();
      //解析routes
       this.createRouteMap();
       //聲明組件
       this.initComponent();
   }
   bindEvents(){
        window.addEventListener('hashchange', this.onHashchange.bind(this))
   }
   onHashchange(){
       this.app.current = window.location.hash.slice(1) || '/'
   }
   createRouteMap(){
      //遍歷用戶配置路由數(shù)組
      this.$options.routes.forEach(route => {
            this.routeMap[route.path] = route;
      })
   }
  initComponent(){
      //轉換目標: <a href = '/'>xx</a>
      // <router-link to = '/'>
     Vue.component('router-link', {
           props: {
                 to: String
           },
           render(h){
                 // h(tag, data,children)
                return h( 'a' , {
                      attrs:{href : '#' + this.to}
                }, [ this.$slots.default ]) // 這里還可以放其他的具名插槽 甚至作用域插槽 
               // 也可以使用jsx
           }
     })
  }
}

最后執(zhí)行一下install方法父泳,把KVueRouter導出一下

export default KVueRouter

這時候可以引入寫好的文件,來調(diào)試一下了

//router.js
import Vue from 'vue'
// import Router from 'vue-router'
import Router from './kvue-router'
import Home from './views/Home.vue'

// 1.應用插件:做了什么吴汪?
Vue.use(Router) // use執(zhí)行了插件install()

// 2.創(chuàng)建Router實例
export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})

在main.js中掛載router

//main.js
import router from './router'
new Vue({
  router, // 配置router實例
  render: h => h(App),
}).$mount("#app");

//app.vue
<div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view></router-view>

這時候我們可以實現(xiàn)路由跳轉了惠窄,但是并不能真正的加載對應的組件,就差渲染內(nèi)容組件了
router-view 這個組件負責實現(xiàn)渲染組件工作漾橙,我們拿出我們要渲染的component

   // 獲取path對應的Component將它渲染出來
    Vue.component("router-view", {
        render: (h) => {
            const Component = this.routeMap[this.app.current].component;
            return h(Component)
        }
    })

另外vue也像我們暴露了一個可以定義一個響應式數(shù)據(jù)的方法

const initial = window.location.hash.slice(1) || ‘/’
Vue.util.defineReactive(this,’current’,initial)

接下來杆融,我們來總結一下
關于實現(xiàn)路由,我們要做的第一件事是實現(xiàn)一個插件install(),這個install方法霜运,會把vue的構造函數(shù)傳進來脾歇,拿到vue的構造函數(shù)之后,我們就可以做很多事情淘捡,接下來我們另一個要實現(xiàn)的kvuerouter里藕各,監(jiān)聽事件,事件發(fā)生變化以后焦除,我們要做的事情把this.app的current的改成新的hash激况,但是為什么修改完新的hash之后,會在router-view把對應的組件渲染出來呢膘魄,原因是只要render函數(shù)里面用到了某個響應式的數(shù)據(jù)乌逐,這個數(shù)據(jù)發(fā)生變化了,我們的組件就會重新執(zhí)行render创葡,這就是典型的依賴收集浙踢,意思就是說render函數(shù)里只要用的data里的東西,就會產(chǎn)生依賴灿渴,編輯器在執(zhí)行render函數(shù)的時候成黄,會先執(zhí)行依賴收集的過程呐芥,先把依賴全部找到,vue里的current只要改變奋岁,和它相關的組件都會發(fā)生改變,也就會導致router-view的component的重新執(zhí)行荸百,界面就渲染了闻伶。
該示例沒有解決嵌套路由的問題,我們可以參考一下官方的文檔够话。

vuex數(shù)據(jù)管理

vuex是一個專門為vue.js應用開發(fā)的狀態(tài)管理模式蓝翰,集中式存儲管理應用所有組件的狀態(tài)。它是一個單項數(shù)據(jù)流的設計思想女嘲,它為了讓數(shù)據(jù)可控畜份,數(shù)據(jù)可追蹤,設計出這樣一個單項數(shù)據(jù)流, 我們在實踐的時候欣尼,也要避免同時被父子組件操作的情況爆雹,維持這樣一個單向的關系,怎么去維系呢愕鼓,我們把一些通用的全局的數(shù)據(jù)钙态,把他抽象到一個store里去保管,只能用不能改菇晃,如果想改數(shù)據(jù)册倒,只能commit一個mutaions,或者dispath一個actions,讓actions去commit一個mutaions磺送,而且在vuex 里面必須實現(xiàn)一個數(shù)據(jù)的響應式驻子,實現(xiàn)的方式也是利用了vuex的構造初始化的時候做了響應式。


vuex

核心概念

state狀態(tài)估灿,數(shù)據(jù)

  • mutations更改狀態(tài)的函數(shù)
  • actions異步操作
  • store包含以上概念的容器

狀態(tài)和狀態(tài)的變更

state保存數(shù)據(jù)狀態(tài)崇呵,mutations用于修改狀態(tài),store.js

export default new Vuex.Store({
      state: {count : 0},
      mutations:{
            increment(state){
                 state.count += 1;
            }
      }
})

vuex的任務分析

  • 實現(xiàn)插件: $store掛載
  • 實現(xiàn)store: 解析vuex配置甲捏,持有state演熟,實現(xiàn)dispatch,commit司顿,getters
  • 借助vue實現(xiàn)數(shù)據(jù)響應式
//kvuex.js
let Vue;
class Store {
  // 持有state芒粹,并使其響應化
  // 實現(xiàn)commit和dispatch兩個方法
  constructor(options) {
    //   數(shù)據(jù)響應式
    // this.state是Vue實例,訪問this.state.count
    this.state = new Vue({ data: options.state });

    this.mutations = options.mutations;
    this.actions = options.actions;
    this.getters = options.getters;

    // bind this
    this.commit = this.commit.bind(this);
    this.dispatch = this.dispatch.bind(this);
    this.getters = this.getters.bind(this);
  }

  //   實現(xiàn)commit:可以修改state中的數(shù)據(jù)
  commit(type, arg) {
    this.mutations[type](this.state, arg);
  }

  dispatch(type, arg) {
    return this.actions[type](this, arg);
  }

 getters(getters){
     //遍歷getters選項大溜,為this.getters定義property
     //屬性名就是選項中的key 化漆,只需定義get函數(shù)保證只讀性
    Object.keys(getters).forEach(key =>{
        Object.defineProperty(this.getters, key, {
           get : () =>{
               return getters[key](this.state)
           }
       })
   })
 }
// 聲明插件install
// _Vue是形參:Vue構造函數(shù),use會把它傳進來
function install(_Vue) {
  Vue = _Vue;

  Vue.mixin({
    beforeCreate() {
      // this指的是組件實例
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store;
      }
    },
  });
}

// 導出Vuex
export default { Store, install };

vuex和vuerouter的實現(xiàn)思想大致相同钦奋,以上在不考慮代碼健壯性的前提下座云,來實現(xiàn)核心思想的疙赠。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市朦拖,隨后出現(xiàn)的幾起案子圃阳,更是在濱河造成了極大的恐慌,老刑警劉巖璧帝,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捍岳,死亡現(xiàn)場離奇詭異,居然都是意外死亡睬隶,警方通過查閱死者的電腦和手機锣夹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苏潜,“玉大人银萍,你說我怎么就攤上這事⌒糇螅” “怎么了贴唇?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赃梧。 經(jīng)常有香客問我滤蝠,道長,這世上最難降的妖魔是什么授嘀? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任物咳,我火速辦了婚禮,結果婚禮上蹄皱,老公的妹妹穿的比我還像新娘览闰。我一直安慰自己,他們只是感情好巷折,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布压鉴。 她就那樣靜靜地躺著,像睡著了一般锻拘。 火紅的嫁衣襯著肌膚如雪油吭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天署拟,我揣著相機與錄音婉宰,去河邊找鬼。 笑死推穷,一個胖子當著我的面吹牛心包,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播馒铃,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蟹腾,長吁一口氣:“原來是場噩夢啊……” “哼痕惋!你這毒婦竟也來了?” 一聲冷哼從身側響起娃殖,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤值戳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后炉爆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體述寡,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年叶洞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片禀崖。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡衩辟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出波附,到底是詐尸還是另有隱情艺晴,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布掸屡,位于F島的核電站封寞,受9級特大地震影響,放射性物質發(fā)生泄漏仅财。R本人自食惡果不足惜狈究,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盏求。 院中可真熱鬧抖锥,春花似錦、人聲如沸碎罚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荆烈。三九已至拯勉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間憔购,已是汗流浹背宫峦。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留倦始,地道東北人斗遏。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像鞋邑,于是被迫代替她去往敵國和親诵次。 傳聞我的和親對象是個殘疾皇子账蓉,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容