【小慕读书】—— 后台管理系统学习:Vue进阶
前言:最近在学习Vue+Element UI+Node.js小慕读书中后台管理系统开发课程,这里对学习过程作个笔记,方便自己和大家翻阅。
一、项目内容
二、技术栈
后端技术栈 Node + Express 架构
jwt: 实现登录认证
epub: epub列树解析
multer: 文件上传
xml2js: xml文件解析
adm-zip: 自定义的电子书解析功能
mysql: 数据库
免费提供的课程API: https://www.youbaobao.xyz/admin-docs/guide/
三、Vue 进阶
1、$emit 和 $on
<div id="root"><button @click="boost">触发事件</button>
</div>
<script>
new Vue({
el: '#root',
data() {
return {
message: 'hello vue'
}
},
created() {
this.$on('my_events', this.handleEvents) //$on定义事件
},
methods: {
handleEvents(e) {
console.log(this.message, e)
},
boost() {
this.$emit('my_events', 'my params') //$emit消费事件
}
}
})
</script>
- 好处:将事件的定义和事件的消费分开,实现逻辑的解耦
可以为同一个事件绑定不同的方法
created() {
this.$on('my_events', this.handleEvents)
this.$on('my_events', this.handleEvents2)
},
可以为不同的事件绑定同一个方法
created() {
this.$on(['my_events', 'my_events2'], this.handleEvents)
console.log(_events)
},
// {
// myevents: [f],
// myevents2: [f]
// }
- this.$emit进行了try...catch的处理,抛出异常不会中断程序的执行
2. directive 用法
<div id="root"><div v-loading="isLoading">{{data}}</div>
<button @click="update">更新</button>
</div>
<script>
Vue.directive('loading', { //loading和v-loading名字一致
update(el, binding, vnode) {
console.log(el, binding, vnode)
if (binding.value) {
const div = document.createElement('div')
div.innerText = '加载中...'
div.setAttribute('id', 'loading')
div.style.position = 'absolute'
div.style.left = 0
div.style.top = 0
div.style.width = '100%'
div.style.height = '100%'
div.style.display = 'flex'
div.style.justifyContent = 'center'
div.style.alignItems = 'center'
div.style.color = 'white'
div.style.background = 'rgba(0, 0, 0, .7)'
document.body.append(div)
} else {
document.body.removeChild(document.getElementById('loading'))
}
}
})
new Vue({
el: '#root',
data() {
return {
isLoading: false,
data: ''
}
},
methods: {
update() {
this.isLoading = true
setTimeout(() => {
this.data = '用户数据'
this.isLoading = false
}, 3000)
}
}
})
</script>
3. Vue.component 用法
<div id="root"><Test :msg="message"></Test>
</div>
<script>
Vue.component('Test', { //定义一个组件
template: '<div>{{msg}}</div>',
props: {
msg: {
type: String,
default: 'default message'
}
}
})
new Vue({
el: '#root',
data() {
return {
message: "Test Component"
}
}
})
</script>
4.Vue.extend 用法
<div id="root"><Test :msg="message"></Test>
</div>
<script>
const component = Vue.extend({ //生成Vue的构造函数VueComponent
template: '<div>{{msg}}</div>',
props: {
msg: {
type: String,
default: 'default message'
}
},
name: 'Test'
})
Vue.component('Test')
new Vue({
el: '#root',
data() {
return {
message: "Test Extend Component"
}
}
})
</script>
5.Vue.extend 进阶用法
- 给Vue实例添加自定义API
<head><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
#loading-wrapper {
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: rgba(0,0,0,.7);
color: #fff;
}
</style>
</head>
<body>
<div id="root">
<button @click="showLoading">显示Loading</button>
</div>
<script>
function Loading(msg) {
const LoadingComponent = Vue.extend({ //创建好构造函数
template: '<div >,
props: {
msg: {
type: String,
default: msg
}
},
name: 'LoadingComponent'
})
const div = document.createElement('div')
div.setAttribute('id', 'loading-wrapper')
document.body.append(div)
//关键:使用$mount将LoadingComponent直接挂载到loading-wrapper上
new LoadingComponent({
props: {
msg: {
type: String,
default: msg
}
}
}).$mount('#loading-wrapper')
return () => {
document.body.removeChild(document.getElementById('loading-wrapper'))
}
}
//构造函数挂载到Vue.prototype
Vue.prototype.$loading = Loading
new Vue({
el: '#root',
methods: {
showLoading() {
//重点:实现this.$loading
const hide = this.$loading('正在加载,请稍等...')
setTimeout(() => {
hide()
}, 2000)
}
}
})
</script>
6.Vue.use 用法
- 把Vue,extends高阶用法——给Vue添加自定义API——做成一个插件
<head><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
#loading-wrapper {
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: rgba(0,0,0,.7);
color: #fff;
}
</style>
</head>
<body>
<div id="root">
<button @click="showLoading">显示Loading</button>
</div>
<script>
const loadingPlugin = {
install: function(vm) { //vm: Vue的构造函数
const LoadingComponent = vm.extend({
template: '<div >,
props: {
msg: {
type: String,
default: 'loading...'
}
}
}, 'LoadingComponent')
function Loading(msg) {
const div = document.createElement('div')
div.setAttribute('id', 'loading-wrapper')
document.body.append(div)
new LoadingComponent({
props: {
msg: {
type: String,
default: msg
}
}
}).$mount('#loading-wrapper')
return () => {
document.body.removeChild(document.getElementById('loading-wrapper'))
}
}
vm.prototype.$loading = Loading
}
}
//关键区别: 通过Vue,use()加载插件
Vue.use(loadingPlugin)
new Vue({
el: '#root',
methods: {
showLoading() {
const hide = this.$loading('正在加载,请稍等...')
setTimeout(() => {
hide()
}, 2000)
}
}
})
</script>
7.组件通信 provide 和 inject
- Vue2.2之后引入的,为了提供更好的跨组件通讯方案
<div id="root"><Test></Test>
</div>
<script>
function registerPlugin() {
Vue.component('Test', {
template: '<div>{{message}}<Test2 /></div>',
//父组件通过provide:提供了将自身组件打包成一个属性elTest提供给子组件调用
provide() {
return {
elTest: this
}
}, // function 的用途是为了获取运行时环境,否则 this 将指向 window
data() {
return {
message: 'message from Test'
}
},
methods: {
change(component) {
this.message = 'message from ' + component
}
}
})
Vue.component('Test2', {
template: '<Test3 />'
})
Vue.component('Test3', {
template: '<button @click="changeMessage">change</button>',
//子组件通过inject获取elTest属性,标识引用到的父组件的实例
inject: ['elTest'],
methods: {
changeMessage() {
//通过this.elTest直接就调用到父组件的change方法,并传入参数
this.elTest.change(this.$options._componentTag)
}
}
})
}
Vue.use(registerPlugin)
new Vue({
el: '#root'
})
</script>
8.过滤器 filter
<div id="root">{{ message | lower }}
</div>
<script>
new Vue({
el: '#root',
filters: {
//过滤器lower:将状态值全部改成小写
lower(value) {
return value.toLowerCase() // hello vue
}
},
data() {
return {
message: 'Hello Vue'
}
}
})
</script>
9.监听器 watch
<div id="root"><h3>Watch 用法1:常见用法</h3>
<input v-model="message">
<span>{{copyMessage}}</span>
</div>
<div id="root2">
<h3>Watch 用法2:绑定方法</h3>
<input v-model="message">
<span>{{copyMessage}}</span>
</div>
<div id="root3">
<h3>Watch 用法3:deep + handler</h3>
<input v-model="deepMessage.a.b">
<span>{{copyMessage}}</span>
</div>
<div id="root4">
<h3>Watch 用法4:immediate</h3>
<input v-model="message">
<span>{{copyMessage}}</span>
</div>
<div id="root5">
<h3>Watch 用法5:绑定多个 handler</h3>
<input v-model="message">
<span>{{copyMessage}}</span>
</div>
<div id="root6">
<h3>Watch 用法6:监听对象属性</h3>
<input v-model="deepMessage.a.b">
<span>{{copyMessage}}</span>
</div>
<script>
new Vue({
el: '#root',
//常见用法1:监听器message后面直接跟一个方法
watch: {
message(value) {
this.copyMessage = value //根据message改变copyMessage的值
}
},
data() {
return {
message: 'Hello Vue',
copyMessage: ''
}
}
})
new Vue({
el: '#root2',
//常见用法2:监听器message后面不再直接跟一个方法,
// 字符串绑定methods中的一个方法名
watch: {
message: 'handleMessage'
},
data() {
return {
message: 'Hello Vue',
copyMessage: ''
}
},
methods: {
handleMessage(value) {
this.copyMessage = value
}
}
})
new Vue({
el: '#root3',
//深度监听1: 监听deepMessage.a.b属性,deep: true
watch: {
deepMessage: {
handler: 'handleDeepMessage', //handler指向一个function
deep: true
}
},
data() {
return {
deepMessage: {
a: {
b: 'Deep Message'
}
},
copyMessage: ''
}
},
methods: {
handleDeepMessage(value) {
this.copyMessage = value.a.b
}
}
})
new Vue({
el: '#root4',
//获得默认值:immediate: true 页面初始化后立即执行了一次handler
watch: {
message: {
handler: 'handleMessage',
immediate: true, //相当于 created: { this.copyMessage = this.message }
}
},
data() {
return {
message: 'Hello Vue',
copyMessage: ''
}
},
methods: {
handleMessage(value) {
this.copyMessage = value
}
}
}),
new Vue({
el: '#root5',
//绑定多个handler: 依次使用
watch: {
message: [{
handler: 'handleMessage',
},
'handleMessage2',
function(value) {
this.copyMessage = this.copyMessage + '...'
}]
},
data() {
return {
message: 'Hello Vue',
copyMessage: ''
}
},
methods: {
handleMessage(value) {
this.copyMessage = value
},
handleMessage2(value) {
this.copyMessage = this.copyMessage + '*'
}
}
})
new Vue({
el: '#root6',
//直接监听对象属性实现深度监听,节约性能
watch: {
'deepMessage.a.b': 'handleMessage'
},
data() {
return {
deepMessage: { a: { b: 'Hello Vue' } },
copyMessage: ''
}
},
methods: {
handleMessage(value) {
this.copyMessage = value
}
}
})
</script>
10.class 和 style 绑定的高级用法
<div id="root"><div :class="['active', 'normal']">数组绑定多个class</div>
<div :class="[{active: isActive}, 'normal']">数组包含对象绑定class</div>
<div :class="[showWarning(), 'normal']">数组包含方法绑定class</div>
<div :style="[warning, bold]">数组绑定多个style</div>
<div :style="[warning, mix()]">数组包含方法绑定style</div>
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">style多重值</div>
</div>
<script>
new Vue({
el: '#root',
data() {
return {
isActive: true,
warning: {
color: 'orange'
},
bold: {
fontWeight: 'bold'
}
}
},
methods: {
showWarning() {
return 'warning'
},
mix() {
return {
...this.bold,
fontSize: 20
}
}
}
})
</script>
四、Vue2.6 新特性
1.Vue.observable
- 比Vuex更方便的使用Vue的响应式属性
<div id="root">{{message}}
<button @click="change">Change</button>
</div>
<script>
const state = Vue.observable({ message: 'Vue 2.6' })
const mutation = {
setMessage(value) {
state.message = value
}
}
new Vue({
el: '#root',
//注意:要在computed中计算响应式属性message的改变
computed: {
message() {
return state.message
}
},
methods: {
change() {
mutation.setMessage('Vue 3.0')
}
}
})
</script>
2.插槽 slot
- v-slot只能用在组件或template上,用在div等标签上会报错
<div id="root"><div>案例1:slot的基本用法</div>
<Test>
<template v-slot:header="{user}">
<div>自定义header({{user.a}})</div>
</template>
<template v-slot="{user}">
<div>自定义body({{user.b}})</div>
</template>
</Test>
</div>
<div id="root2">
<div>案例2:Vue2.6新特性 - 动态slot</div>
<Test>
<template v-slot:[section]="{section}">
<div>this is {{section}}</div>
</template>
</Test>
<button @click="change">switch header and body</button>
</div>
<script>
Vue.component('Test', {
template:
'<div>' +
'<slot name="header" :user="obj" :section="\'header\'">' +
'<div>默认header</div>' +
'</slot>' +
'<slot :user="obj" :section="\'body\'">默认body</slot>' +
'</div>',
data() {
return {
obj: { a: 1, b: 2 }
}
}
})
new Vue({ el: '#root' })
new Vue({
el: '#root2',
data() {
return {
section: 'header'
}
},
methods: {
change() {
this.section === 'header' ?
this.section = 'default' :
this.section = 'header'
}
}
})
</script>
注:项目来自慕课网
以上是 【小慕读书】—— 后台管理系统学习:Vue进阶 的全部内容, 来源链接: utcz.com/z/379949.html