文章目录
12. 内置指令
P40 v-text
……
P41 v-html
v-html比起v-text来说可以解析html标签
![image-20210818170229065](Images/image-20210818170229065.png)
PS:这一节还讲到一个很有趣的东东,xss攻击,具体看视频吧
P42 v-cloak
需要配合css使用,v-cloak是只有Vm加载时才会消失,所以配合display:none 可以实现js堵塞时,不会出现混乱 的html内容
![image-20210818171356017](Images/image-20210818171356017.png)
P43 v-once
只进行初始化渲染,后面就变成静态内容
P44 v-pre
跳过节点编译过程,提高性能
12a.自定义指令
P45 函数式
![image-20210824184131587](Images/image-20210824184131587.png)
p:这里改变了元素的内容
P46 对象式
首先补充下原生dom操作
<title>Document</title>
<style>
.demo{
background-color: orange;
}
</style>
<script type="text/javascript" >
const btn = document.getElementById('btn')
btn.onclick = ()=>{
const input = document.createElement('input')
//以下操作可以放元素加载(插入页面)之前
input.className = 'demo'
input.value = 99
input.onclick = ()=>{alert(1)}
//元素插入页面
document.body.appendChild(input)
//必须要在元素插入后,进行focus方法
input.focus()
}
</script>
正文
<body>
<div id="root">
<h2>当前的n值是:<span v-text="n"></span> </h2>
<h2>放大10倍后的n值是:<span v-big="n"></span> </h2> /P:绑定了big自定义事件
<button @click="n++">点我n+1</button>
<hr/>
<input type="text" v-fbind:value="n"> //P:绑定了fbind自定义事件
</div>
</body>
<script type="text/javascript">
new Vue({
data:{
n:1
},
directives:{
big(element,binding){
console.log('big',this) //注意此处的this是window
element.innerText = binding.value * 10
},
fbind:{
//P:以下操作可以顺序可以参考上面的dom操作
//指令与元素成功绑定时(一上来)
bind(element,binding){ //P:element是可以操作的原生dom
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
}
}
})
</script>
P47 总结
对上面两节的总结和一些其他补充
需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
自定义指令总结:
一、定义语
(1).局部指令
new Vue({ new Vue({
directives:{指令名:配置对象} 或 directives{指令名:回调函数}
}) })
(2).全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
二、配置对象中常用的3个回调:p:就是完整的写法
(1).bind:指令与元素成功绑定时调用。
(2).inserted:指令所在元素被插入页面时调用。
(3).update:指令所在模板结构被重新解析时调用。
三、备注:
1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
//这里只展示补充的,完整代码要结合上两节
<div id="root">
<h2>当前的n值是:<span v-text="n"></span> </h2>
<h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2>
//多个单词指令名要采用kebab-case方式
<button @click="n++">点我n+1</button>
<hr/>
<input type="text" v-fbind:value="n">
</div>
<script type="text/javascript">
//定义全局指令
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
})
new Vue({
data:{
n:1
},
directives:{
'big-number':(element,binding){ //P:冒号可以加可以不加,不知道为什么可以不加?
element.innerText = binding.value * 10
},
}
})
</script>
13. 生命周期
P48 周期介绍
生命周期就是组件的”一生"
后P内容也需参考下图:
![image-20210819145636862](Images/生命周期.png)
P49 挂载流程
具体内容看流程图和视频
这节主要讲了两个点可以了解下:Vue.template和vm.$mount
这两个点会影响周期的过程和挂载内容(具体看视频)
![image-20210819145636862](Images/image-20210819145636862.png)
这节讲到初始化过程为止(mouted之前)
P50 更新流程
数据更新了触发,对新旧虚拟DOM比较,更新页面
beforeUpdate数据页面尚未同步
Upated数据页面同步
如图:
![image-20210819161619871](Images/image-20210819161619871.png)
P51 销毁流程
vm.$destroy触发
官网这里所写的事件监听器是指自定义的事件,不包括像onclick这样的dom原生事件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q2cZjZE7-1652603393459)(Images/image-20210819161236275.png)]
在beforeDestroy()中修改数据,虽然改了但不会更新到页面的,直接进入destroy()
销毁钩子:
![image-20210819161517781](Images/image-20210819161517781.png)
P52 总结
如图
![image-20210819163903920](Images/image-20210819163903920.png)
14. 组件
P53 对组件的理解
组件的定义:实现应用中局部功能代码(HTML\JS\CSS)和资源(MP3\IMG\FONT)的集合
作用:复用js,简化js的编写,提高js运行效率
名词解释
- 模块化
当应用中的js都以模块来编写,那这个应用就是一个模块化的应用
- 组件化
当应用中功能都是多组件的方式来编写的,这个应用就是一个模块化的应用
![image-20210819170645359](Images/image-20210819170645359.png)
如上图可以看出组件化是包括模块化的(毕竟js文件是包括在组件里的)
P54 非单文件组件
非单文件和单文件区别
![image-20210819173515044](Images/image-20210819173515044.png)
单文件组件
![image-20210819173330866](Images/image-20210819173330866.png)
P55 组件注意点
可以使用name配置项指定组件在开发者工具中呈现的名字(如果没有指定,就按注册名来 )
在开发大型组件和第三方库是可以用到name,感觉主要还是为了语义化
![image-20210819175559241](Images/image-20210819175559241.png)
P56 组件嵌套
例子
![image-20210819190901958](Images/image-20210819190901958.png)
Root是vm之下,万件之上的“宰相”
P57 VueComponent
如图
![image-20210819192956920](Images/image-20210819192956920.png)
P58 Vue实例与组件实例
vc和vm虽然很像,但还是有些点不同
- vm里的el,vc没有,
- vm能写data:{},vc不能写
![image-20220515093136794](Images/image-20220515093136794.png)
P59 内置关系(js补充)
首先要明白JS原型链
![image-20210820105501182](Images/image-20210820105501182.png)
内置关系
![image-20210820105143818](Images/image-20210820105143818.png)
P60 单文件组件
name最好还是加上,不然调试工具里的名字会按,import的name来展示
![image-20210820135201566](Images/image-20210820135201566.png)
Main.js中import App组件不用脚手架不行,因为浏览器不支持es6模块化语法。
这节简单过了一遍脚手架的基本解析流程,整理了main.js\html\app.vue\others.vue间的关系
15. 脚手架
P61 创建脚手架
npm install -g @vue/cli ##全局安装vuecli
vue create xxxx ##创建项目-切换到创建项目的目录
npm run serve ##启动项目-
补充
- 下载缓慢解决
配置npm淘宝镜像:npm config set registry https://registry.npm.taobao.org
5:35 淘宝镜像
old note
babel文件的作用是把es6转成es5
package-lock.json的功能是锁定包管理版本
P62 分析脚手架
<%= BASE_URL %>就是指从public文件夹下找(防止写./…/这些时出现各种问题,用这个保险hh)
![image-20210820151928099](Images/image-20210820151928099.png)
基础脚手架的内容除了render都介绍了
P63 render函数
main.js
如图:这节讲到一些node_modules-vue里内容
![image-20210820155247600](Images/image-20210820155247600.png)
App.vue
组件里的template则有这个框架解析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mw020MYb-1652603393460)(Images/image-20210820155525758.png)]
P64 修改默认配置
vue.config.js(修改配置,可选)
webpack基于Nodejs,node用的就是commonjs暴露方法,所以 vue.config.js用的是module.export
vue.config.js修改了一定要重启
语法检查(公司没规定可以关闭,不然影响编程效率)
在配置文件中加这段可以取消“烦人”的语法检查
![image-20210820162250024](Images/image-20210820162250024.png)
16. 组件配置项
P65 ref属性
本来用document.getElementid() 就能实现,但如果要获取的是完整Vue组件的话,就需要使用ref
![image-20210820172114521](Images/image-20210820172114521.png)
P66 props配置
vue组件属性值必须要加(key-‘value’)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g0xDKnwo-1652603393461)(Images/image-20210820185309566.png)]
加了v-bind才能写数值,因为这里是表达式[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6mPUbpZF-1652603393462)(Images/image-20210820185532122.png)]
三种写法如图:
![image-20210820193708201](Images/image-20210820193708201.png)
P67 mixin混入
PS:混合就是公用vue配置,用js文件来写对象(一般都是统一或者部分暴露)
![image-20210821113032876](Images/image-20210821113032876.png)
P68 插件
以Vue构造函数为参数,可以实现全局属性的集合(过滤器、指令、混入 ……)
具体如图:
![image-20210821140219788](Images/image-20210821140219788.png)
P69 scoped样式
Vue cli 用的webpack版本是4.x[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Po3m62RW-1652603393463)(Images/image-20210821142131581.png)],而有些插件(less-loader)的最新版本是针对webpack5.x的,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWKeug6y-1652603393464)(Images/image-20210821142425822.png)]安装会报错,所以需要安装这些版本webpack4.x旧版(less-loader7.x)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBYSHNnk-1652603393467)(Images/image-20210821142336348.png)]
![image-20210821142630567](Images/image-20210821142630567.png)
17. TodoList案例
P70 静态
把传统html项目改为vue项目和拆分组件
P71 初始化列表
声明了一些state,并通过props传参
P73 添加
实现了添加方法,主要用到兄弟间通信最基础实现(状态提升)
补充
不使用v-model,用原生dom操作实现双向绑定
<input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add"/>
//这里使用了最原生的dom操作实现
props:['addTodo'],
methods: {
add(e){
const todoObj = {id:nanoid(),title:e.target.value,done:false
//:e.target.value-获取到页面输入值
this.addTodo(todoObj)
e.target.value = '' //这里直接赋值可以修改input-value,说实话没想到
}
},
nanoid
插件比uuid插件更轻量级
import {nanoid} from 'nanoid'
export default {
methods: {
add(){
const todoObj = {id:nanoid(),title:this.title,done:false}
//数组对象的id需要保证为唯一值,不然b可能会
}
},
}
P74 删除
核心
deleteTode(id){
this.todos =this.todos.filter(todo=>todo.id!==id) //filter不改变原数组
}
- 原生确认框
handleDelete(id){
if(confirm("确定删除吗?"){ //confirm是原生的对话框
console.log(id)
})
}
P75 底部统计
核心
donetotal(){
//使用reduce来统计已选项数
const x =this.todos.reduce((pre,current)=>{
//最后循环的return作为整个reduce()的return
console.log("@",pre,current)
return pre+(current.done?1:0) //return作为下次循环的pre
},0)
//精简版
return this.todos.reduce((pre,current)=>pre+(current.done?1:0),0)
}
P76 底部交互
code
1.MyFooter.vue
<template>
<label>
<!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> -->
<!-- 对于输入类型的节点:这两个方法可以用v-model简化-->
<input type="checkbox" v-model="isAll"/>
</label>
</template>
computed: {
//总数
total(){
return this.todos.length
},
//已完成数
doneTotal(){
return this.todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0) ,0)
},
//控制全选框
isAll:{ //配置v-model实现输入类型方法简写化
get(){
return this.doneTotal === this.total && this.total > 0 //计算属性套娃
},
set(value){
this.checkAllTodo(value)
}
}
}
2.App.vue
todos:[
{id:'001',title:'抽烟',done:true},
{id:'002',title:'喝酒',done:false},
]
//清除所有已经完成的todo
clearAllTodo(){
this.todos = this.todos.filter((todo)=>{
//使用filter过滤-最优解
return !todo.done
})
}
P77 总结
正文
- 文档
- props适用于:父子间通信
- v-model绑定的值不能是props传过来的值,因为props是不可以修改的!??
- props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。??
others
open in external app
可以让我们在vscode中右键直接打开md文件
注:但是试了下,没反应
P89 编辑 <-
code
1.MyItem.vue
<input
:value="todo.title"
@blur="handleBlur(todo,$event)"
//$event是关键词吗?有别的随便写的变量不同吗
//P:随便查了下:说是可以获取到该事件的事件对象-应该是vue做处理过
ref="inputTitle"
>
//js
props:['todo'],
handleEdit(todo){ //编辑任务
if(todo.hasOwnProperty('isEdit')){
//注:这里没有用todo.isEdit,因为结果为空和”布尔值为假“都可以为false
//hasOwnProperty-对象自身是否具有指定的属性
todo.isEdit = true
}else{
//todo.isEdit = true-这写法数据能改变但Vue不会响应
this.$set(todo,'isEdit',true) //添加对象属性的正确写法
//P:有人可能会问为什么要怎么麻烦,直接一开始写好属性值不行吗?
//如果data传入数据有isEdit最好,没有的话还是要用到这种方法添加属性
}
}
//失去焦点回调-真正执行修改逻辑
handleBlur(todo,e){
todo.isEdit = false
if(!e.target.value.trim()) //trim()-去除字符串的头尾空格
return alert('输入不能为空!')
this.$bus.$emit('updateTodo',todo.id,e.target.value)
}
P90 $nextTick <-
code
<span v-show="!todo.isEdit">{{todo.title}}</spa>n>
<input v-show="todo.isEdit" ref="inputTitle">
<button @click="handleEdit(todo)">编辑</button>
handleEdit(todo){
……
//this.$refs.inputTitle.focus()-失效,因为Vue的处理逻辑是先执行方法再重新编译
//虽然todo.isEdit已经是true了,但是模板还没有编译,页面还没"v-show"<input\>元素
this.$nextTick(function(){ //nextTick能让其回调函数在DOM更新后执行
this.$refs.inputTitle.focus()//获取input焦点
})
},
正文
- 文档
- 作用:在下一次 DOM 更新后执行其指定的回调。
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。(感觉就是看当前语句执行要不要依赖”基于之前语句更新后"的dom)
18. 本地存储
P78 浏览器本地存储
code
<!-- localStorage和sessionStorage的api相同-只是生命周期不一样-->
<!DOCTYPE html>
<html>
<body>
<h2>localStorage</h2>
<button onclick="saveData()">点我保存一个数据</button>
<!-- html文件里的标签绑定事件不能省略“()”-->
<button onclick="readData()">点我读取一个数据</button>
<button onclick="deleteData()">点我删除一个数据</button>
<button onclick="deleteAllData()">点我清空一个数据</button>
<script type="text/javascript" >
let p = {name:'张三',age:18}
function saveData(){
localStorage.setItem('msg','hello!!!')//修改和新增数据
//这里还省略了windows-应该是html是默认从window上找方法
localStorage.setItem('msg2',666)
//如果不是String类型,浏览器也会自动进行String转换
localStorage.setItem('person',JSON.stringify(p))
//注:这个要stringify转换下,不然浏览器把对象类型自动String转换-value会变为[Object Object]
}
function readData(){
console.log(localStorage.getItem('msg'))//获取数据
console.log(localStorage.getItem('msg2'))
const result = localStorage.getItem('person')
//const result2 = localStorage.getItem('person2')
//如果person2对应的value获取不到,那么getItem的返回值是null。
console.log(JSON.parse(result))
//console.log(JSON.parse(person2))
//JSON.parse(null)的结果依然是null。
}
function deleteData(){
localStorage.removeItem('msg2')//删除数据
}
function deleteAllData(){
localStorage.clear()//清空数据
}
</script>
</body>
</html>
正文
- 文档
-
存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
-
浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。
-
相关API:
Storage.setItem('key', 'value');
该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。Storage.getItem('person');
该方法接受一个键名作为参数,返回键名对应的值。Storage.removeItem('key');
该方法接受一个键名作为参数,并把该键名从存储中删除。Storage.clear()
该方法会清空存储中的所有数据。
-
备注:
- SessionStorage存储的内容会随着浏览器窗口关闭而消失。
- LocalStorage存储的内容,需要手动清除才会消失。(浏览器设置or引导用户点击删除按钮)
others
- 控制台storage几个常用操作
![image-20220202134632428](Images/image-20220202134632428.png)
P79 本地存储
code
<div class="todo-wrap">
<MyHeader :addTodo="addTodo"/>
<MyList :todos="todos" ……/>
<MyFooter :todos="todos" ……/>
</div>
export default {
data() {
return {
todos:JSON.parse(localStorage.getItem('todos')) || [] //对于没有数据的情况要给个初始值,不然容易报错-undefined
}
},
watch: {
todos:{
deep:true,//这个的监听属性要使用完整写法来深度拷贝-否则不能更新到{{isDone:value}}的数据
handler(value){
localStorage.setItem('todos',JSON.stringify(value))
//这里没可以省略window-??html\vue为什么能省略window
}
}
},
}
19. 组件自定义事件
P80 绑定
code
子向父传参推荐使用自定义事件,代码更简洁,更符合模式
1.App.vue(父组件)
<h1>{msg}},学生姓名是:{{studentName}}</h1>
<School :getSchoolName="getSchoolName"/>
<!-- props实现 -->
<Student @atguigu="getStudentName" />
<!-- getStudentName是作为事件的回调??去使用 -->
<!-- 自定义事件实现-第一种写法 -->
<Student ref="student" @click.native="show"/>
<!-- 自定义事件实现-第二种写法,p:虽然写法复杂,但是更灵活如搞个定时器 -->
<script>
export defaul t {
studentName:''
//methods
getSchoolName(name){
this.studentName = name //School.vue
},
getStudentName(name,...params){
//...params是es6-把后面的参数都放在一个数组[x,y,]
this.studentName = name //Student.vue
},
show(){
alert(123)
}
mounted() {
setTimeout(()=>{
this.$refs.student.$on('atguigu',this.getStudentName)
//用$refs绑定自定义事件-如果是$once则为一次性事件
},
},3000 )
}
</script>
2.School.vue(子组件-使用prop)
<button @click="sendSchoolName">把学校名给App</button>
<script>
export default {
props:['getSchoolName'],//props方法需要接收
name:'尚硅谷',
//methods
sendSchoolName(){
this.getSchoolName(this.name)
},
}
</script>
3.Student.vue(子组件-使用自定义事件)
<h2>学生姓名:{{name}}</h2>
<button @click="sendStudentlName">把学生名给App</button>
<script>
export default {
name:'张三',
//methods
sendStudentlName(){
this.$emit('atguigu',this.name,666,888,900)
//触发Student组件实例身上的atguigu事件
},
}
</script>
正文
- 自定义和原生JS事件区别
一个给html元素,一个给组件用
P81 解绑
code
//3.Student.vue-P80 code
<h2>学生姓名:{{name}}</h2>
<h2>当前求和为:{{number}}</h2>
<button @click="add">点我number++</button>
<button @click="unbind">解绑atguigu事件</button>
<button @click="death">销毁当前Student组件的实例(vc)</button>
<script>
export default {
name:'张三',
number:0
//methods
add(){ //组件销毁后原生dom事件依然能使用-只是没响应了??
this.number++
},
unbind(){
this.$off('atguigu') //解绑一个自定义事件
// this.$off(['atguigu','demo'])-解绑多个
// this.$off()-解绑所有
},
death(){
this.$destroy()
//销毁了当前Student组件的实例-实例的自定义事件全都不奏效。
}
}
</script>
正文
- $destroy销毁副作用
如图也能销毁绑定的自定义事件等等,并且销毁父组件会联并销毁子组件
P82 总结
code
1.app.vue
<!--<Student ref="student" @click="show"/>-->
<!-- click是给html元素使用的,如果给组件绑定vue会处理为自定义事件 -->
<!-- 如果要触发这click方法只能用自定事件那套语法 -->
<Student ref="student" @click.native="show"/>
<!-- 加native才能让组件绑定原生事件 -->
show(){
alert("show")
}
2.student.vue
<template>
<div class="student">
</div>
<!--<div/>-->
<!-- 不能有两个跟组件的部分原因-如果有两个跟组件像上面的click.native事件就不知道该绑定到哪个标签上了 -->
</template>
正文
-
自定义事件原则-给谁绑定事件就找谁触发事件
-
文档
1.使用场景:A是父组件,B是子组件,子传父,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
2.绑定自定义事件:
第一种方式,在父组件中:<Demo @atguigu="test"/>
或 <Demo v-on:atguigu="test"/>
第二种方式,在父组件中:
<Demo ref="demo"/>
......
mounted(){
this.$refs.xxx.$on('atguigu',this.test)
}
若想让自定义事件只能触发一次,可以使用 once
修饰符,或 $once
方法。
3.触发自定义事件:this.$emit('atguigu',数据)
4.解绑自定义事件 this.$off('atguigu')
5.组件上也可以绑定原生DOM事件,需要使用 native
修饰符。
注:通过 this.$refs.xxx.$on('atguigu',回调)
绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
//这是一种正确写法
this.$refs.student.$once('atguigu',(name,...params)=>{
console.log('App收到了学生名:',name,params)
this.studentName = name
})
P83 Todo案例
……
P:这些p看下来发现可能自定义事件和props函数,写法都差不多呀,就是自定义事件的话可以不用**接收函数props:[‘fn1’]**这样。
因为自定义函数实际上是给子组件绑定了一个自定义事件,真正起作用的是里面的回调函数,而且这个函数还是定义在父组件的。
others
- 开发者工具看自定义事件
![image-20220202212152787](Images/image-20220202212152787.png)
20. 事件总线
P84 全局事件总线1
正文
- 全局事件总线作用-任意组件间通信
![image-20220204132722224](Images/image-20220204132722224.png)
- 全局事件总线实现前提
1.所有组件都能访问
2.能使用**$on、off、emit**
想到使用window
//window.x={a:1,b:2}
这样不好一般来说没人会在window上面放东西
想到使用vc的原型对象VueComponents
//VueComponent.prototype.x={a:1,b:2}
这样写报错undefined,因为VueComponents构造函数是vue.extend生成的(不能直接使用,应该是vue自动调用了-在每一次创建组件时)
每次调用vue.extend,返回的都是一个新的VueComponent
那直接在源码改呢?-执行力很强的杠精
//vue.runtime.esm.js-源码
var Sub=function VueComponent(options){
this._init(options)
}
//Sub.prototype.x={a:1,b:2}
这样改是有效的,但是太离谱
发现一个重要的内置关系VueComponent.prototype._proto_===Vue.prototype??
这个关系可以让vc(组件实例对象)直接访问到Vue原型上的属性和方法
![image-20220204134837908](Images/image-20220204134837908.png)
//正解
1.main.js
import Vue from 'vue'
Vue.prototype.x={a:1,b:2}
2.School.vue
mounted(){
console.log("school",this.x)
}
P85 全局事件总线2
code
![image-20220204144729489](Images/image-20220204144729489.png)
1.main.js
import Vue from 'vue'
import App from './App.vue'
//使用vc实现
//const Demo =Vue.extend({})
//const demo=new Demo()
//Vue.prototype.x=demo-d就是vc
//使用vm-更标准更简化
new Vue({
el:"#app",
render:h=>h(App),
beforeCreate(){
//添加$bus需要在Vue构建函数中并用到beforeCreate
Vue.prototype.$bus=this //安装全局事件总线
//为什么叫总线-bus还有总线的意思
}
})
2.school.vue
mounted(){
this.$bus.$on('hello',data=>{
console.log("定义了全局自定义事件hello",data)
})
}
beforeDestroy(){
this.$bus.$off('hello')
//注:这里必须要解绑-因为自定义事件是定义在vm上的、作用全局
}
3.student.vue
this.$bus.$emit('hello',{a:1}) //调用全局自定义事件并提供数据
P86 Todo案例
code
1.main.js
new Vue({
el:'#app',
render:h=>h(App),
beforeCreate(){
Vue.prototype.$bus=this //安装全局总线
}
})
2.App.vue //定义和解绑事件
mounted(){
this.$bus.$on('checkTode',this.checkTode)
this.$bus.$on('deleteTode',this.deleteTode)
}
beforeDestroy(){
this.$bus.$off('checkTode')
this.$bus.$off('deleteTode')
}
3.MyItem.vue
handleCheck(id){
this.$bus.$emit('checkTode',id)//触发事件
}
others
- 控制台查看总线-一般是by**<Root>**
![image-20220204153542090](Images/image-20220204153542090.png)
21. 订阅与发布
P87 消息订阅与发布
5:20js原生不行用第三方库 10:20~订阅消息 11:09发布消息 - code 13:48>取消订阅 -文档 17:30总线和订阅选择
import pubsub from 'pubsub-js'
1.school.vue
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)//msgName-订阅号名称
})//订阅消息
beforeDestroy() {
pubsub.unsubscribe(this.pubId)//取消订阅-定时器一样有个id(pubId)
},
2.student.vue
sendStudentName(){
pubsub.publish('hello',666) //发布消息
}
正文
- 实现方式
原生比较难实现消息订阅与发布-需要用到第三方库 pubsub-js
- 总线和订阅选择
禹神推荐使用总线,毕竟是vue2原生,实现写法和效果都大相径庭。
P:而且开发者工具能监听$bus,订阅发布不行
others
- 订阅(subscribe)、发布(publish)
P88 Todo案例
……
P89-90->
other
- 对于不用的形参可以用
_
充当占位符
deleteTode(_,id){xxx}
22. 过度与动画
P91 动画效果-
P92 过度效果-
P93 多个元素过度-
code
<transition-group >
<!-- 标签包涵多个元素需要用group,并记得加Key -->
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">尚硅谷!</h1>
</transition-group>
<transition name="hello" appear><!-- appear-初始化时就出现动画 -->
<!-- P:<transition>的原理应该是vue会自动解析class名称,遇到关键动画class就动态添加 -->
<h1 v-show="isShow">你好啊!</h1>
</transition>
<style scoped>
1.动画
.hello-enter-active{
/* 如果上面没写name属性,就用v-enter-active(默认、全局) */
/*enter-vShow为true,leave-vShow为false */
animation: donghua 0.5s linear;
}
.hello-leave-active{
animation: donghua 0.5s linear reverse; /*reverse-反向 */
}
/*css3动画-帧*/
@keyframes donghua {
from{
transform: translateX(-100%);
}
to{
transform: translateX(0px);
}
}
2.过度(transition标签还是配合动画css好用)
h1{
background-color: orange;
/* transition: 0.5s linear;-不用active的话transition也可以写在这 */
}
/* 进入的起点、离开的终点 */
.hello-enter,.hello-leave-to{
transform: translateX(-100%);
}
/* 过程中 */
.hello-enter-active,.hello-leave-active{
transition: 0.5s linear;
}
/* 进入的终点、离开的起点 */
.hello-enter-to,.hello-leave{
transform: translateX(0);
}
</style>
P:过度效果的原理逻辑目前不是很懂,有缘再看
正文
- 使用控制台可见vue自动添加了一些class
![image-20220204205206009](Images/image-20220204205206009.png)
P94 集合第三方动画
<transition-group
appear
name="animate__animated animate__bounce" //固定写法-官网有写
enter-active-class="animate__swing" //这些动效可以去官网看
leave-active-class="animate__backOutUp"
>
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">尚硅谷!</h1>
</transition-group>
<script>
import 'animate.css' //在这里引入库-没有输出东西直接用
</script>
正文
P95 总结+Todo案例
code
<transition-group name="todo" appear>
<MyItem
v-for="todoObj in todos"
:key="todoObj.id"
/>
</transition-group>
<style scoped>
.todo-enter-active{ /*注:使用特殊名称来区分实现、配合动画css实现更佳(也可以用过度哈)*/
animation: donghua 0.5s linear;
}
.todo-leave-active{
animation: donghua 0.5s linear reverse;
}
@keyframes donghua {
from{
transform: translateX(100%);
}
to{
transform: translateX(0px);
}
}
</style>
正文
- 文档
- 作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。
- 图示:
- 写法:
- 准备好样式:
- 元素进入的样式:v-enter、v-enter-active、v-enter-to
- 元素离开的样式:v-leave、v-leave-active、v-leave-to
- 使用
<transition>
包裹要过度的元素,并配置name属性: - 注:若有多个元素需要过度,则需要使用:
<transition-group>
,且每个元素都要指定key
值。
- 准备好样式:
固定写法-官网有写
enter-active-class=“animate__swing” //这些动效可以去官网看
leave-active-class=“animate__backOutUp”
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">尚硅谷!</h1>
`正文`
- [animate.css官网](https://www.npmjs.com/package/animate.css)
### P95 总结+Todo案例
`code`
```vue
<transition-group name="todo" appear>
<MyItem
v-for="todoObj in todos"
:key="todoObj.id"
/>
</transition-group>
<style scoped>
.todo-enter-active{ /*注:使用特殊名称来区分实现、配合动画css实现更佳(也可以用过度哈)*/
animation: donghua 0.5s linear;
}
.todo-leave-active{
animation: donghua 0.5s linear reverse;
}
@keyframes donghua {
from{
transform: translateX(100%);
}
to{
transform: translateX(0px);
}
}
</style>
正文
- 文档
- 作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。
- 图示:
- 写法:
- 准备好样式:
- 元素进入的样式:v-enter、v-enter-active、v-enter-to
- 元素离开的样式:v-leave、v-leave-active、v-leave-to
- 使用
<transition>
包裹要过度的元素,并配置name属性: - 注:若有多个元素需要过度,则需要使用:
<transition-group>
,且每个元素都要指定key
值。
- 准备好样式: