【小慕读书】—— 后台管理系统学习:Vue进阶

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>

  • 好处:将事件的定义和事件的消费分开,实现逻辑的解耦

  1. 可以为同一个事件绑定不同的方法

    created() {

    this.$on('my_events', this.handleEvents)

    this.$on('my_events', this.handleEvents2)

    },

  2. 可以为不同的事件绑定同一个方法

    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

回到顶部