课程目标
- vue的状态管理
- SSR
知识点
- vuex3
MVC:model 、view、controller
M:dataV:html+cssc:jsMVVM:model、view、viewmodelM:dataV:html+cssVM:双向绑定
面试题
MVVM的理解
- 区别:抛弃对
dom的严格感知
- 无需对流程的过过程化操作
- 写法上、代码可维护
vue的组件传值
单例模式,只能有一个实例。
- 父子传值
propson $emit$parent
- 兄弟节点
- 通过父节点
eventBusprovideinjectattrslistenersvuex
vuex 是单例模式,vue-router也是单例,全局只能有一个。如果复杂的话,可以考虑vuex-module模块处理。
vuex
component -- actions -- mutations -- states -- component
- 为何要兜一圈?
action可能会有async存在 ,vuex是同步过程 - 异步如何转同步?
- 比如
promise怎么转同步,可以用.then.thenes
<script>
exprot default {
name: 'app',
method: {
asyncFunc() {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
console.info('async');
})
})
}
},
async mounted() {
this.asyncFun.then(res => {
console.info('mouted');
})
//es语法
await this.asyncFun();
console.info('mounted');
}
}
</sript>
如果有多个异步怎么办?会涉及到串联,串联有两种方式:全部执行和竞争执行
<script>
exprot default {
name: 'app',
method: {
asyncFunc() {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
console.info('async');
})
})
},
asyncFunc2() {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
console.info('async 2');
})
})
}
},
async mounted() {
this.asyncFun().then(res => {
console.info('mouted');
})
//es语法
await this.asyncFun();
console.info('mounted');
//多个异步怎么执行?全部执行
Promise.all([this.asyncFunc(), this.asyncFunc2()]).then(() => {
console.info("all done");
});
//竞争执行
Promise.race([this.asyncFunc(), this.asyncFunc2()]).then(() => {
console.info("all done");
});
//多个异步依赖执行,比如表单提交依赖
//可以使用一个比较笨的方法
await this.asyncFun();
await this.asyncFun2();
//还可以使用`co库` -- 简单实现 - 迭代器模式
const pipeLine = [this.asyncFun, this.asyncFun2]
//先有一个迭代器 永远执行下一个
setIterator(pipeLine)
//next() - function* + yield - 生成器
function* setGenerator(pipeLine) {
for(const fn of pipeLine) {
yield fn()
}
}
//迭代器模式。配置迭代器 - main
function setIterator(pipeLine) {
const generator = setGenerator(pipeLine)
GFC(generator)
}
//流水线 区分同步异步,依次执行
function GFC(gen) {
const item = gen.next();
if(item.done) {
return item.value
}
//value是内容,done是状态
const {value, done } = item;
//判断是同步还是异步的
if(value instanceof Promise) {
//递归调用下一个
value.then(e => GFC(gen));
}else{
//直接执行
GFC(gen);
}
}
}
}
</sript>
vuex创建及使用
// store/index.js
improt Vue from 'vue'
improt Vuex from 'vuex'
// use上
Vue.use(Vuex)
//创建store实例
const store = new Vuex.Store({
actions: {
setNodeInfo({ commit }, info) {
//可以做异步处理
commit('SET_NODE_INFO', {
info
})
}
},
mutations: {
SET_NODE_INFO(sate, { info }) {
state.nodeInof = info
}
},
state: {
nodeInfo: {
name: '-',
age: 0
}
}
})
exprot default store;
//dispatch的用法
this.$store.dispatch('setNodeInfo', this.nodeInfo);
//获取全局store
this.$store.state.nodeInfo;
还有其它四种方式为store提供便捷的辅助函数。
mapState
improt { mapState } from 'vuex';
//使用方法:三种方法都可以
//第一种
...mapState(['nodeInfo'])
//第二种
...mapSate({
nodeInfo: state => state.nodeInfo
})
//第三种
this.$store.state.nodeInfo;
vuex3主要基于mixin
//mixin.js 源码
//面试可能会提问到,vuex什么时候进行的初始化,是在beforeCreate时初始化的。
Vue.mixin({ beforeCreate: vuexInit })
//store injection 源码
//store注入到每个实例中
function vuexInit()
//store.js 源码
let Vue;
//实例对象的描述
exprot class Store {
constructor (option = {}) {
//cdn直接引用的方式,可以自动instally
if(!Vue && typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
}
}
//1.挂载
//use时候的开始
export function install( _Vue ) {
}
//面试题:vuex自定义了告警,为啥不用console.assert? - throw Error 是为了把进程打断。
//面试题:Object.create(null)和{}的区别:区别在于原型链
//Object.create(null).__prototype__为undefined,就可以规避掉其它原型链上的东西。
//{}.__prototype__是Object.prototype
//...
//因为是单例模式,确认this是当前store的实例
const store = this;
const { displatch, commit } = this;
this.dispatch = function boundDispatch (type, payload) {
return dispatch.call(store, type, payload);
}
this.commit = function boundCommit(type, payload, options) {
return commit.call(store, type, payload, options);
};
//init all modules
installModule(this, state, [], this._modules.root)
//reset vm,vue是怎么做响应式的
resetStoreVM(this, state)
function resetStoreVM(store, state, hot) {
const oldVm_ = store._vm;
//...
const computed = {}
forEachValue(wrappedGetters, (fn, key) => {
computed[key] = partial(fn, store)
//遍历地将所有getters桥接上store,并配置成computed属性
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true
})
})
//...
//利用vue的能力,做响应式
store._vm = new Vue({
data: {
$$state: state
},
computed
})
//...
//销毁
if( oldVm ){
if( hot ){
store._withCommit(() => {
oldVm_.data.$$state = null;
})
}
Vue.nextTick(() => oldVm.$destory())
}
}
vuex4主要基于provide
SSR
SSR一般只用于首页。
- 优点:首屏
- 缺点:不利于
SEO搜索,server压力大,如果服务器给力就没啥问题
- 建立服务
npm i vue-server-renderer express -D:是一个服务端渲染器,用于渲染vue的。
- 搭建node服务
//server/index.js
//0.加载依赖
const express = require('express');
const Vue = require('vue');
const app = express()
const renderer = require('vue-server-renderer').createRenderer();
//渲染器渲染page得到html内容
//1.page
const page = new Vue({
template: '<div>hello,ssr</div>'
})
//2.传递接口
app.get('/', async(req, res) => {
try {
const html = await renderer.renderToString(name);
res.send(html);
} catch(error) {
res.status(500).send('server inner error');
}
})
//3. 启动监听服务
app.listen(3000, () => {
console.info('server start');
})
- 执行nodejs文件
- 路由文件写法
//router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '../component/HelloWorld.vue'
Vue.use(Router)
//传统路由写法
//exprot default new Router({
//routers: [{
//path: '/',
//name: 'hello world',
//component: HelloWorld
//}]
//})
//ssr路由写法
//面试题:为什么会这样写?为什么不导出一个router?
//因为用户的每个请求都要创建一个实例
exprot default function createRouter() {
return new Router({
routers: [{
path: '/',
name: 'hello world',
component: HelloWorld
}]
})
}
//app.js
import Vue from 'vue'
import App from './App.vue'
import createRouter from '../router'
exprot default function createApp() {
const router = createRouter();
const app = new Vue({
router,
render: h => h(App)
})
return { app, router }
}