Vue-router
Vue Router 是 Vue.js 官方的路由管理器,它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。
安装:
vue add router
核心步骤:
-
使用 vue-router 插件,router.js
import Route from 'vue-router' Vue.use(Router)
-
创建 Router 实例,router.js
export default new Router({...})
-
在根组件上添加该实例,main.js
import router from './router' new Vue({ router }).$mount('#app')
-
添加路由视图,App.vue
<router-view></router-view>
-
导航
<router-link to='/'>Home</router-link> <router-link to='/about'>About</router-link>
vue-router 源码实现
单页面应用程序中,URL 发生变化,不刷新并显示对应的视图内容
需求分析
-
spa 点击链接不能出刷新页面
-
hash #xxx
-
history api
-
-
事件 hashchange,通知 router-view 更新
-
利用 Vue 数据响应式
-
制作一个响应式数据表示当前 URL,在 router-view 的 render 函数使用它
-
任务
-
实现一个插件
-
实现 VueRouter 类
-
实现 install 方法
-
-
实现两个全局组件
-
router-link
-
router-view
-
创建 kvue-router.js
// 插件
let KVue
// 1. 实现一个install方法
class VueRouter {
constructor(options) {
this.$options = options
// 响应式数据
const initial = window.location.hash.slice(1) || '/'
KVue.util.defineReactive(this, 'current', initial)
// this.current = '/'
// 监听事件
window.addEventListener('hashchange', this.onHashChange.bind(this))
window.addEventListener('load', this.onHashChange.bind(this))
// 缓存path和route映射关系
this.routeMap = {}
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route
})
}
onHashChange () {
this.current = window.location.hash.slice(1)
console.log(this.current)
}
}
// 形参是Vue构造函数
KVueRouter.install = function (Vue) {
// 保存构造函数(独立的包,不希望将vue也打包进去)
KVue = Vue
// 1. 挂载$router
Vue.mixin({
beforeCreate () {
// 全局混入,将来在组件实例化的时候才执行
// 此时Vue实例已经存在了
// this指的是组件实例
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
// 2. 实现两个全局组件
Vue.component('router-link', {
props: {
to: {
type: String,
required: true
}
},
// h是createElement函数
render (h) {
// <a href='#/xxx'></a>
// h(tag,props,children)
// jsx语法也可以用
// return <a href={'#' + this.to}>{this.$slots.default}</a>
return h(
'a',
{
attrs: {
href: '#' + this.to
}
},
this.$slots.default
)
}
})
// rouetr-view 是一个容器
Vue.component('router-view', {
render (h) {
// 1. 获取路由器实例
// const routes = this.$router.$options.routes
// const current = this.$router.current
// const route = routes.find(route => route.path === current)
// const comp = route ? route.component : null
const { routeMap, current } = this.$router
const comp = routeMap[current] ? routeMap[current].component : null
// 获取路由表 eg:'/'===home组件
// return h('div','view')
return h(comp)
}
})
}
export default KVueRouter
Vuex 原理
Vuex 集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。

整合 vuex
vue add vuex
核心概念
- state 状态、数据
- mutations 更改状态的函数
- actions 异步操作
- store 包含以上概念的容器
状态 - state
state保存应用状态
export default new Vuex.Store({
state: { counter:0 },
})
状态变更 - mutations
mutations用于修改状态,store.js
export default new Vuex.Store({
mutations: {
add (state) {
state.counter++
}
}
})
派生状态 - getters
从state派生出新状态,类似计算属性
export default new Vuex.Store({
getters: {
doubleCounter (state) { // 计算剩余数量
return state.counter * 2;
}
}
})
动作 - actions
添加业务逻辑,类似于 controller
export default new Vuex.Store({
actions: {
add ({ commit }) {
setTimeout(() => {
commit('add')
}, 1000);
}
}
})
测试代码:
<p @click="$store.commit('add')">counter: {{$store.state.counter}}</p>
<p @click="$store.dispatch('add')">async counter: {{$store.state.counter}}</p>
<p>double:{{$store.getters.doubleCounter}}</p>
原理解析
任务
-
实现⼀个插件:声明Store类,挂载$store
-
Store具体实现:
-
创建响应式的 state,保存 mutations、actions 和 getters
-
实现 commit 根据用户传入 type 执行对应 mutation
-
实现 dispatch 根据用户传入 type 执行对应 action,同时传递上下文
-
实现 getters,按照 getters 定义对 state 做派生
-
代码实现:
let KVue
// 实现 Store 类
class Store {
constructor(options) {
// 保存 mutations
this._mutations = options.mutations
// 保存 actions
this._actions = options.actions
// 绑定 this 到 store 实例
// 绑定 commit 上下⽂否则 action 中调⽤ commit 时可能出问题!!
// 同时也把 action 绑了,因为 action 可以互调
const store = this
const { commit, action } = store
this.commit = function boundCommit (type, payload) {
commit.call(store, type, payload)
}
this.action = function boundAction (type, payload) {
return action.call(store, type, payload)
}
// getters
// 1. 遍历用户传入 getters 所有 key,动态赋值,其值应该是函数执行结果
// 2. 确保它是响应式的,Object.defineProperty(this.getters,key,{get(){}})
// 3. 缓存结果,可以利用 computed
let computed = {}
options.getters && this.handleGetters(options.getters, computed)
// 响应式的 state
this._vm = new KVue({
data: {
$$state: options.state
},
computed
})
}
handleGetters (getters, computed) {
this.getters = {}
Object.keys(getters).forEach(key => {
computed[key] = () => getters[key](this.state)
Object.defineProperty(this.getters, key, {
get: () => getters[key](this.state),
enumerable: true,
})
})
}
get state () {
return this._vm._data.$$state
}
set state (v) {
console.error('请重新设置' + v + '的名称')
}
// commit(type,payload):执行 mutation,修改状态
commit (type, payload) {
// 根据 type 获取对应的 mutations
const entry = this._mutations[type]
if (!entry) {
console.error('这是未知的 mutation 类型')
return
}
entry(this.state, payload)
}
// dispatch(type,payload)
dispatch (type, payload) {
const entry = this._actions[type]
if (!entry) {
console.error('这是未知的 action 类型')
return
}
return entry(this, payload)
}
}
// 实现插件
function install (Vue) {
KVue = Vue
// 混入
Vue.mixin({
beforeCreate () {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
// 此处导出的对象理解为 Vuex
export default { Store, install }
网友评论