Vue学习笔记
数据绑定:
单向绑定(v-bind):数据只能从data流向页面
双向绑定(v-model):数据不仅能从data流向页面,也能从页面流向data
el的两种写法:
new Vue时配置el属性
先创建vue实例,随后再通过vm.$mount('#root')指定el的值
data的两种写法:
对象式
函数式——学习到组件时,必须使用函数式
按键:
大多数的按键都可以配合keyup使用,除了ctrl、alt、shift、meta需要用keydown
时间修饰符:
prevent:阻止默认事件(常用)
stop:阻止冒泡
once:事件只触发一次
capture:使用事件的捕获模式
self:只有event.target是当前的操作元素时才触发
计算属性:
定义:要用的属性不存在,要通过已有属性计算
原理:底层借住Object.defineproperty提供的get和set函数实现
get函数:初次读取时会调用一次;当依赖发生变化时会再次调用
优势:与methods相比,内部有缓存机制
监视属性:
当被监视的属性变化时,回调函数自动调用
监视的两种写法:通过new Vue时的watch配置;通过vm.$watch监视
深度监测:vue中的watch默认不监测对象内部值的变化,配置deep:true可以监测对象内部值变化
监视的写法如下:
//完整写法 ...... watch: { isHot: { immediate:true,//初始化时让handler调用一下
deep:true, handler(newValue, oldValue) { console.log('isHot被修改了', newValue, oldValue) } } } //简写,只执行handler watch:{ isHot(newValue, oldValue){ console.log('isHot被修改了', newValue, oldValue } }
//正常写法
vm.$watch('isHot', {
immediate:true
......
}
//正常缩写
vm.$watch('isHot', function(newValue, oldValue){
console.log('isHot'被修改了,newValue, oldValue, this)
}
computed和watch之间的区别:
computed能完成的功能,watch都可以完成
watch能完成的功能,computed不一定能完成,例如watch可以进行异步操作
被Vue管理的函数,最好写成普通函数;不给Vue管理的函数,最好写成箭头函数
绑定样式:
class样式写法:
class=“xx" xx可以是字符串、对象、数组
字符串写法用于: 类名不确定,要动态获取
对象写法用于: 要绑定多个样式,个数不确定,名字也不确定
数组写法用于: 要绑定多个样式,个数确定,名字确定,但不确定用不用
style样式:
:style="{fontSize: xxx}"其中xxx是动态值
:style="{a, b}" 其中a,b是样式对象
条件渲染:
v-if:适用于频率较低场景;不展示的DOM直接被移除;v-if和v-else-if和v-else之间不能被打断
v-show:适用于频率较高的场景;不展示的DOM元素未被移除,仅仅使用样式隐藏
<template v-if="type === '0'"> <el-button size="small" >AAA</el-button> <el-button size="small" >SQL拉取-Doris </el-button> </template>
数据监测:
对象中数据通过setter实现监视,且要在new Vue时传入要监测的数据
(1):对象中后追加的属性,Vue默认不做响应式处理,如vm.object.xxx = "xxx"
(2):如需给后添加属性做响应式,需要使用以下API:
Vue.set(target, propertyName/index, value)或 vm.$set(target, propertyName/index, value)
数组中数据通过包裹数组更新元素的方法实现
(1):调用原生对应的方法对数组进行更新
(2):重新解析模板,进而更新页面
修改数组中的某个元素需要使用以下API:
(1):push()、pop()、shift()、unshift()、splice()、sort()、reverse()
(2):Vue.set()、vm.$set()此两方法不能给vm或vm._data数据对象添加属性
收集表单数据:
<input type="text"/>,则v-model收集的是value值,用户输入的就是value值
<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值
<input type="checkbox"/>
1:没有配置input的value属性,那么收集的就是checked(是否勾选,为布尔值)
2:配置input的value属性:
(1):v-model初始值是非数组,那么收集的就是checked(是否勾选,为布尔值)
(2):v-model初始值是数组,那么收集的就是value组成的数组
Vue其它指令:
v-text:向其所在节点渲染文本内容,{{x}}不会
v-html:向指定节点渲染包含html结构内容,会替换所有内容,{{x}}不会,有安全性问题
v-cloak:本质是特殊属性,Vue实例创建完毕后会被删除;配合css可以解决网速慢显示出{{xx}}问题
v-once:所在节点在初次动态渲染后,转为静态内容,可用于优化性能
v-pre:跳过节点编译过程;不使用指令语法、键值语法的节点,会加快编译
Vue生命周期:
refs:
1:被用来给元素或子组件注册引用信息(id的替代者)
2:应用在html标签上获取的是真实DOM元素, 应用在组件标签上是组件实例对象(vc)
3:使用方式:
打标识: <h1 ref="xxx"> ......</h1> 或 <School ref="xxx"></School>
获取:this.$refs.xxx
props:
1:传递数据:<Demo name="xxx" />
2:接收数据:
第一种方式(只接收):
props:['name']
第二种方式(限制类型):
props: {
name:Number
}
第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String, //类型
required:true, //必要性
default: '老王' //默认值
}
}
3:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制内容到data中一份,然后去修改data中数值
props类型:
mixin(混入):
功能:可以把多个组件公用的配置提取成一个混入对象
使用方式:
第一步定义混合,例如:
{
data(){....},
methods:{....}
}
第二步使用混入,例如
1:全局混入:Vue.mixin(xxx)
2:局部混入: mixins:['xxx']
插件:
功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后参数是插件使用者传递的数据
定义插件:
对象:install = function (Vue, options) {
Vue.filter(....) // 1.添加全局过滤器
Vue.directive(....) // 2.添加全局指令
Vue.mixin(....) // 3.配置全局混入(合)
Vue.prototype.$myMethod = function() {...}
Vue.prototype.$myProperty = xxxx
}
使用插件:Vue.use()
scoped样式:
作用:让样式在局部生效,防止冲突
写法:<style scoped>
WebStorage:
1:存储内容大小一般支持5MB左右(不同浏览器可能不同)
2:浏览器通过window.sessionStorage 和 window.localStorage属性来实现本地存储机制
3:相关API:
xxxxStorage.setItem('key', 'value') // 该方法接受一个键和值做参数,会将键值对添加进存储中,如键名存在,则更新其对应的值
xxxxStorage.getItem('key') //该方法接受一个键名作参数,返回键名对应的值
xxxxStorage.removeItem('key') //该方法接受一个键名作参数,并把该键名从存储中删除
xxxxStorage.clear() // 该方法会清空存储中的所有数据
4:
(1)SessionStorage中存储的内容会随着浏览器关闭而消失
(2) LocalStorage存储的内容,需要手动清除才会消失
(3) xxxxStorage.getItem(xxx)如果取不到对应的值,则返回值是null
(4)JSON.parse(null)结果依然是null
Vue与VueComponent的关系:
vue脚手架配置代理:
方法一:vue.config.js中添加如下配置
devServer: { proxy: "http://localhost:5000" }
(1)优点:配置简单,请求资源时直接发给前端(8080)即可
(2)缺点:不能配置多个代理,不能灵活的控制请求是否走代理
(3)工作方式:若按照上述配置代理,当请求了前端不存在的资源时,该请求会转发给服务器
方法二:编写vue.config.js配置具体代理规则:
module.exports = { devServer: { proxy: { '/api1': { target: 'http://localhost:5000', // 代理目标的基础路径 changeOrigin: true, pathRewrite: {'^/api1': ''} }, '/api2': { target: 'http://localhost:5000', // 代理目标的基础路径 changeOrigin: true, pathRewrite: {'^/api1': ''} }, } } } // changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000 // changeOrigin设置为false时,服务器收到的请求头中的host为: localhost:8000 // changeOrigin默认为true
(1)优点:可以配置多个代理,且可以灵活的控制请求是否走代理
(2)缺点:配置略微你繁琐,请求资源时必须加前缀,如 http://localhost:8080/api1/students
组件自定义事件->子传父(3种方式)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//第一种 <template> <School :getSchoolName = "getSchoolName"></School> </template> methods:{ getSchoolName(value){ console.log('我收到了数据:', value) }, } //在子组件中触发 props:['getSchoolName'], methods:{ sendSchoolName(){ this.getSchoolName(this.name) } } //第二种 <template> <Student @demo="m1"></Student> </template> methods:{ m1(){ console.log('demo被触发了') } } //在子组件中触发,之后需要执行this.$off methods:{ sendStudentName(){ this.$emit('demo') }, unbind(){ //this.$off('atguigu') //this.$off(['atguigu', 'demo']) this.$off() }, death(){ this.$destroy() } } //第三种 <template> <Student @atguigu="getStudentName" ref="student"></Student> </template> methods:{ getSchoolName(value){ console.log('我收到了数据:', value) }, getStudentName(value, ...params){ console.log('我收到了数据', value, params) }, } mounted(){ this.$refs.student.$on('atguigu', this.getStudentName) } //在子组件中触发,之后需要执行this.$off methods:{ sendStudentName(){ this.$emit('atguigu', this.name, 2224, 332, 322) }, unbind(){ //this.$off('atguigu') //this.$off(['atguigu', 'demo']) this.$off() }, death(){ this.$destroy() } }
组件上也可以绑定原生DOM事件,需要使用native修饰符
全局事件总线(适用于任意组件间通信):
1:安装全局事件总线
new Vue({ render: h => h(App), beforeCreate(){ Vue.prototype.$bus = this } }).$mount('#app')
2:使用事件总线
//接收数据 methods:{ checkTodo(id){ this.todos.forEach((todo) => { if (todo.id === id) todo.done = !todo.done }) }, } mounted(){ this.$bus.$on('checkTodo', this.checkTodo) }, beforeDestroy(){ this.$bus.$off('checkTodo') } //发送数据 methods: { //勾选or取消勾选 handleCheck(id){ //通知App组件将对应的todo对象的done值取反 // this.checkTodo(id) this.$bus.$emit('checkTodo',id) },
插槽
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 1:默认插槽,父组件 <HelloWorld title="美食" :listData="foods"> <img src="./test.jpg" alt=""> </HelloWorld> // 子组件HelloWorld,<slot>标签会对应显示<img>内容 <template> <div class="category"> <h3>{{title}}分类</h3> <slot></slot> </div> </template> // 2:具名插槽,父组件 <div id="app"> <HelloWorld title="美食" :listData="foods"> <img slot="center" src="./test.jpg" alt=""> <div slot="footer">更多美食</div> </HelloWorld> <HelloWorld title="游戏"> <ul slot="center"> <li v-for="(g, index) in games" :key="index">{{games}}</li> </ul> <template v-slot:footer> <div class="foot" > <div>网络游戏</div> <div>单机游戏</div> </div> <h4>hahaha</h4> </template> </HelloWorld> </div> // 子组件HelloWorld <div class="category"> <h3>{{title}}分类</h3> <slot name="center"></slot> <slot name="footer"></slot> </div> // 3.作用域插槽,父组件,以下两个template等同 <HelloWorld title="美食"> <template scope="{foods}"> <ul> <li v-for="(g, index) in foods" :key="index"> {{g}} </li> </ul> </template> <template slot-scope="atguigu"> <ul> <li v-for="(g, index) in atguigu.foods" :key="index"> {{g}} </li> </ul> </template> </HelloWorld> //子组件HelloWorld <template> <div class="category"> <h3>{{title}}分类</h3> <slot :foods="foods"></slot> </div> </template> export default { name: 'HelloWorld', data() { return { foods:['火锅','烧烤', '小龙虾'], } }, }
Vuex:
Vue3项目结构
关于main.js文件
setup
setup注意点
ref函数
reactive函数
vue3的响应式
实现原理:
通过Proxy(拦截):拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、删除等
通过Reflect(反射):对源对象的属性进行操作
reactive对比ref
vue3——computed
vue3——watch,监视ref
监视reactive
watchEffect
vue3生命周期
与vue的差距大体只在最后部分
hook函数
shallowReactive与shallowRef
readonly与shallowReadonly
toRaw与markRaw
customRef
响应式数据的判断
新的组件
Fragment
Teleport
Suspense