第一节、概念
<标签 v-xx
v-xx:vue提供了内置指令:v-for、v-if、v-show、v-html....
每一个指令都有自己的功能,实现具体的业务
今后总有一些业务我们通过vue自带的指令是无法实现,那么我们就可以采用自定义指令来实现
所谓的自定义指令本质就是将一段业务封装成一个指令(v-xx)
第二节、分类
1 全局自定义指令(用得较多)
一旦定义后在任意组件中能够使用
js中
import Vue from 'vue'
Vue.directive('自定义指令名字',{功能..})
2 局部自定义指令
只能在当前组件中生效
vue中
directives:{
'指令名称1':{
功能。。。
}
}
第三节、自定义指令的三个钩子函数
1 bind(){} ,只会在初始化时调用一次,当指令绑定到某个元素时生效
2 inserted(){} ,在bind之后执行,当被绑定的元素挂载到页面时才会生效 (可能触发多次)
3 update(){} 元素更新时触发
第四节、全局自定义指令
demo1:页面上有两个文本框,当页面加载完毕后指定某一个文本框获取焦点
- 新建目录和文件:src/directives/index.js
- 编辑index.js
import Vue from 'vue'
Vue.directive('getFocus',{
//参数1:被绑定的原生标签对象
//参数2:绑定对象.value 获取=后面的值
inserted(el,binding){
console.log(el,binding.value);
//业务 (玩的原生dom方法)
el.focus()
}
})
- main.js
//自定义指令生效
import '@/directives/index.js'
- 把自定义指令绑定到某个标签中
<input type="checkbox" v-getFocus>
demo2:渲染所有学生的头像,如果某些图片加载失败,则显示默认图
- 编辑自定义指令
//让异常图片默认显示
Vue.directive('showIsImgError',{
//参数1:被绑定的原生标签对象
//参数2:绑定对象.value 获取=后面的值
inserted(el,binding){
// console.log(el,binding.value);
//业务 (玩的原生dom方法)
el.onerror=function(){
el.src=binding.value
}
}
})
- 编辑vue
<template>
<div>
<img
width="100px"
height="100px"
v-for="(item,index) in arr"
:key="index"
:src="`http://localhost:3000/img/${item}`"
v-showIsImgError="defaultImg"
/>
</div>
</template>
<script>
export default {
data(){
return{
arr:[],
defaultImg:require('@/assets/logo.png')
}
},
async created(){
let res=await this.$http.stus.getAll()
console.log(res.result);
this.arr=res.result.map(item=>item.head)
}
}
</script>
<style>
</style>
第五节、$nextTick
如果我们需要在元素加载完毕后,操作节点时,需要用到mounted,但是如果节点的内容是异步获取的,那么mount就没意义了,
因为mounted钩子函数是同步代码,同步代码会比异步代码先执行,导致我们在数据返回前就提前操作了,如何解决?
采用 this.
n
e
x
t
T
i
c
k
(
)
,
该
a
p
i
能够等到全部异步任务都执行完毕后,页面最终挂载完毕后才会执行语法
:
t
h
i
s
.
nextTick() ,该api能够等到全部异步任务都执行完毕后,页面最终挂载完毕后才会执行 语法: this.
nextTick(),该api能够等到全部异步任务都执行完毕后,页面最终挂载完毕后才会执行语法:this.nextTick(()=>{业务})
注意:该语法必须紧挨着数据变动的后面
<template>
<div>
<p id="p">{{name}}</p>
</div>
</template>
<script>
export default {
data(){
return{
name:""
}
},
created(){
setTimeout(() => {
this.name='hello'
//该语法必须放在赋值数据的后面
this.$nextTick(()=>{
console.log(document.getElementById("p").innerHTML);
})
},100);
},
}
</script>
<style>
</style>
虚拟dom概念:
如果我们改变了数据后,vue不会立马渲染,而是异步渲染(中间会等待一定的时间)
第六节、全局注册组件
目前的操作都属于局部注册组件:
1 import 引入组件
2 components注册组件
3 当成标签来使用
- 局部注册组件的好处
会随着父组件的销毁而销毁,不会一直占用内存 - 局部注册组件的坏处
每次都需要重复注册方可使用
全局组件:
一旦注册完之后,会一直占用内存,以后可以直接把该组件当成标签用于任意组件
全局注册组件的方式:
方式1:直接在main.js中注册
//全局注册组件
import MyTable from '@/globalComponents/MyTable.vue'
Vue.component('globalTable',MyTable)
方式2:直接在main.js中注册
//全局注册组件
import MyTable from '@/globalComponents/MyTable.vue'
Vue.use({
install:function(){
Vue.component('globalTable',MyTable);
}
})
第七节、excel导出
参考:
https://blog.csdn.net/m0_59023970/article/details/123427008
步骤:
- 下载插件
npm install vue-json-excel --save
- 全局注册组件
import JsonExcel from 'vue-json-excel'
Vue.component('downloadExcel', JsonExcel)
- 使用
<download-excel
class="export-excel-wrapper"
:data="DetailsForm"
:fields="json_fields"
:header="title"
name="web89_stu_list.xls"
>
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
<el-button type="success">导出</el-button>
</download-excel>
//导出excel相关
DetailsForm: [
{
date: "2022-3-10",
details: "卸油区过路灯损坏",
measure: "更换灯泡",
timeLimit: "2022-3-21",
plan: "先使用充电灯代替,贴好安全提醒告示",
personInCharge: "王xx",
preparer: "王xx",
fund: "20元",
complete: "已完成整改",
remark: "重新更换了灯泡",
},
],
json_fields: {
"排查日期":'date',
"整改隐患内容":'details',
"整改措施":'measure',
"整改时限":'timeLimit',
"应急措施和预案":'plan',
"整改责任人":'personInCharge',
"填表人":'preparer',
"整改资金":'fund',
"整改完成情况":'complete',
"备注":'remark',
},
title: "沙皮狗集团",
作用:点击按钮,导出当前页的学生记录(除了头像都需要导出)
第八节、vue中的过渡动画
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果
在以下情况方可使用动画
- 条件渲染(v-if/v-show)
- 动态组件
Demo 点击按钮,以动画的形式隐藏显示元素
<template>
<div>
<button @click="flag=!flag">点击</button>
<transition enter-active-class="xx-enter-active" leave-active-class="xx-leave-active">
<span v-show="flag">沙皮狗</span>
</transition>
</div>
</template>
<script>
export default {
data(){
return{
flag:true
}
}
}
</script>
<style scoped>
@keyframes change{
0%{
opacity: 0;
}
100%{
opacity: 1;
}
}
.xx-enter-active{
animation: change 2s
}
.xx-leave-active{
animation: change 2s reverse
}
</style>
Demo 点击按钮,以动画的形式隐藏显示元素 --简化
<template>
<div>
<button @click="flag=!flag">点击</button>
<transition name="xx">
<span v-show="flag">沙皮狗</span>
</transition>
</div>
</template>
<script>
export default {
data(){
return{
flag:true
}
}
}
</script>
<style scoped>
@keyframes change{
0%{
opacity: 0;
}
100%{
opacity: 1;
}
}
.xx-enter-active{
animation: change 2s
}
.xx-leave-active{
animation: change 2s reverse
}
</style>
demo2: 点击按钮以动画的方式来改变内容时
<template>
<div>
<button @click="flag=!flag">点击</button>
<transition name="xx">
<span v-if="flag" key="1">张三</span>
<span v-else key="2">李四</span>
</transition>
</div>
</template>
<script>
export default {
data(){
return{
flag:true
}
}
}
</script>
<style scoped>
@keyframes change{
0%{
opacity: 0;
}
100%{
opacity: 1;
}
}
.xx-enter-active{
animation: change 1s
}
.xx-leave-active{
animation: change 0s reverse
}
</style>
demo3: 列表过度
<template>
<div>
<input type="text" v-model="t" @keyup.enter="add" />
<ul style="margin-left: 80px">
<transition-group name="xx">
<li v-for="item in arr" :key="item.id">
{{ item.title }}
<button @click="del(item.id)">删除</button>
</li>
</transition-group>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
t: "",
arr: [
{ id: 1, title: "aa" },
{ id: 2, title: "bb" },
{ id: 3, title: "cc" },
],
id: 4,
};
},
methods: {
add() {
this.arr.push({
id: this.id++,
title: this.t,
});
},
del(id) {
this.arr = this.arr.filter((item) => item.id != id);
},
},
};
</script>
<style scoped>
@keyframes change {
0% {
opacity: 0;
transform: translateX(-80px);
}
100% {
opacity: 1;
transform: translateX(0px);
}
}
.xx-enter-active {
animation: change 1s;
}
.xx-leave-active {
animation: change 1s reverse;
}
</style>