讲解在同名B/D上都有,主要介绍一些跟业务无关的代码技巧
注: 部分内容主观性较大,一家之言姑且听之
本文主要介绍异步属性
的二次封装
问题
根节点处会包含某个接口信息的获取,获取后属性会存在sessionStorage
或内存
中
- 根目录
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(ElementUI);
const api = function () {
return new Promise(resolve => setTimeout(() => {
resolve({
id: 2,
name: "2xx"
})
}, 1000))
}
new Vue({
async beforeCreate() {
/**
* 登录或刷新你的时候请求
* 但不希望 在路由处使用 loading
* 数据本身存在vuex或sessionStorage中
*/
sessionStorage.removeItem("user")
const data = await api()
sessionStorage.setItem("user", JSON.stringify(data))
},
render: h => h(App),
}).$mount('#app')
- 使用数据
此处会获取
sessionStorage
用以获取缓存中的数据,但因为是异步的,此处选择使用setTimeout
进行处理
注:也可以使用路由的方式,路由拦截会产生白屏问题,作者使用了setTimeout的思路解决,但显然这里也可能有问题
<template>
<div id="app">
</div>
</template>
<script>
export default {
beforeCreate() {
setTimeout(() => {
try {
const user = JSON.parse(sessionStorage.getItem("user"))
console.log(user, "user")
// 获取到user以后,根据userid进行请求操作
// axios.get(`/api/user/${id}`)
} catch (error) {
}
},2000)
}
}
</script>
优化1
- 注册
定义属性的get/set
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(ElementUI);
const api = function () {
return new Promise(resolve => setTimeout(() => {
resolve({
id: 2,
name: "2xx"
})
}, 1000))
}
new Vue({
async beforeCreate() {
const resolves = []
// 挂载到全局上,子组件可以使用this.$root.user使用
Object.defineProperty(this, 'user', {
get() {
return new Promise((resolve) => {
const user = JSON.parse(sessionStorage.getItem("user"))
if (user) {
return resolve(user)
} else {
resolves.push(resolve)
}
})
},
set(data) {
resolves.forEach(resolve => resolve(data));
sessionStorage.setItem("user", JSON.stringify(data))
}
})
sessionStorage.removeItem("user")
const data = await api()
sessionStorage.setItem("user", JSON.stringify(data))
},
render: h => h(App),
}).$mount('#app')
- 使用
使用时,使用this.$root.user
进行获取
<template>
<div id="app">
</div>
</template>
<script>
export default {
async beforeCreate() {
const user = await this.$root.user
console.log(user,'user')
}
}
</script>
优化2
希望将代码抽象到js文件中,这里将对应的定义提取到user中
export function buildUser(scope) {
const resolves = []
Object.defineProperty(scope, 'user', {
get() {
return new Promise((resolve) => {
const user = JSON.parse(sessionStorage.getItem("user"))
if (user) {
return resolve(user)
} else {
resolves.push(resolve)
}
})
},
set(data) {
resolves.forEach(resolve => resolve(data));
sessionStorage.setItem("user", JSON.stringify(data))
}
})
async function loadUser() {
sessionStorage.removeItem("user")
const data = await api()
scope.user = data
}
return loadUser
}
const api = function () {
return new Promise(resolve => setTimeout(() => {
resolve({
id: 2,
name: "2xx"
})
}, 1000))
}
优化3
但上面的问题在于 依赖this的指向,将this的指向抽离,包含两种写法,这里使用class
的方式
- 模型定义
/**
* 模型的定义
* 状态管理是模型的一种变体
*/
class User {
constructor() {
this._resolves = []
}
get data() {
return new Promise((resolve) => {
const user = JSON.parse(sessionStorage.getItem("user"))
if (user) {
return resolve(user)
} else {
this._resolves.push(resolve)
}
})
}
set data(data) {
this._resolves.forEach(resolve => resolve(data));
sessionStorage.setItem("user", JSON.stringify(data))
}
async loadUser() {
sessionStorage.removeItem("user")
const data = await api()
this.data = data
}
}
export const user = new User()
- 模型事件触发
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(ElementUI);
import { user } from './user'
new Vue({
async beforeCreate() {
user.loadUser()
},
render: h => h(App),
}).$mount('#app')
- 模型属性的使用
<template>
<div id="app">
</div>
</template>
<script>
import { user } from './user'
export default {
async beforeCreate() {
const userData = await user.data
console.log(userData, 11)
}
}
</script>
什么是模型
模型是用来描述前端数据的来源,以及序列化的内存结构,他是mvvm中的m,与vm没有任何关系,通常可以率先定义,使用模型层可以极大的解耦
通常,状态管理是模型层的一种变体,可以不用状态管理,但不能不理解模型