Vue基础
1.差值表达式可以放值和表达式
{{message}}
{{if(flag)?yes:no}}
2.v-html
会将其子元素覆盖,有xss攻击风险。
3.computed与watch的区别
computed有缓存;watch没有
computed: {
now: function () {
return Date.now()
}
}
computed是用来属性直接计算,而watch是监听属性的。
比如姓和名组成名字
computed:{
姓名:function(){
return 姓+名
}
}
watch:{
姓:function,
名:function
}
watch还有几个属性
watch:{
某属性:{
handler:fun => 改变时会执行的函数
immediate: true/false(默认) =>是否一刷新就执行handler
}
}
4.watch如何监听引用类型
要用深度监听,但引用类型是拿不到oldValue的
user:{
name:'xxx',
info:{
age:'222',
city:'xxx',
...
}
}
watch:{
info:{
handler(o,v){
watch info
}
deep:true
}
}
5.v-if 和v-show有什么区别
v-if可以跟v-else配合使用
v-if="false"的时候 会将组件从DOM树上移除,更新不频繁的时候用。
v-show="false"的时候会将组件display属性设置为none
只是隐藏显示组件的话,还可以使用动态组件
6.v-for
遍历对象
<li v-for="(item,index) in List" :key="唯一的值就行">{{item}}</li>
如果要使用v-if 在li的父元素上用,不要在li上用。
List可以是数组、对象
7.事件
<div @click="noParam">不带形参</div>
<div @click="haveParam(123,$event)">带形参</div>
methods: {
noParam(e) {
console.log(e.target)
},
haveParam(num) {
console.log(num, event.target)
},
}
8.父子组件通信
props和$emit
const TestComponent = {
name: "TestComponent",
props: ["count"],
emit: ["update:count"],
methods: {
handleClick() {
this.$emit("update:count", this.count + 1)
},
},
template: `<div>
<p @click="handleClick">{{count}}</p>
</div>`,
}
const app = Vue.createApp({
components: { TestComponent },
data() {
return {
count: 1,
}
},
template: `
<div>
<test-component v-model:count="count" />
</div>`,
})
const vm = app.mount("#root")
自定义事件
<sub-component @myevent="handleEvent"></sub-component>
//in sub-component
this.$emit("myevent",param)
//in app
handleEvent(param){
//do sth
}
另一种方法,event.js
return new Vue()
import event from "event.js"
//in sub-component
event.$emit("myevent",param)
//在app的mounted()里绑定
event.$on("myevent",this.handleEvent)
//记得在销毁组件的时候,解绑自定义事件,否则会造成内存泄漏
beforeDestroy(){
event.$off("myevent",this.handleEvent)
}
9.组件生命周期
单个组件:4个阶段,8种。
/*
生成vue实例
*/
//生成之前
beforeCreate() {
console.log("beforeCreate->", root.innerHTML)
},
//生成之后
created() {
console.log("create->", root.innerHTML)
},
/*
编译template(若有)/编译innerHTML
*/
//将页面内容替换为template之前
beforeMount() {
console.log("beforeMount->", root.innerHTML)
},
//将页面内容替换为template之后
mounted() {
console.log("mounted->", root.innerHTML)
},
/*
数据更新
*/
//更新数据,但页面更新之前
beforeUpdate() {
//在控制台更改数据
//vm.$data.message="xxx"
console.log("beforeUpdate->", root.innerHTML) //<p>hello world</p>
},
//页面更新之后
updated() {
console.log("updated->", root.innerHTML) //<p>xxx</p>
},
/*
卸载vue实例
*/
//卸载但更新之前
beforeUnmount() {
//在控制台使用
//app.unmound()
console.log("beforeUnmount->", root.innerHTML)
//<!-- template --><div><p>hello world</p></div><!-- /template -->
},
//更新之后
unmounted() {
console.log("unmounted->", root.innerHTML) //空
},
})
const vm = app.mount("#root")
其中beforeUnmount对应beforeDestroyed,unmounted对应destroyed
父子组件:事件从外到内,渲染从内到外
父 beforeCreate
父 created
父 beforeMount
子 beforeCreate
子 created
子 mounted
父 mounted
父 beforeUpdate
子 beforeUpdate
子 updated
父 updated
父 beforeDestroyed
子 beforeDestroyed
子 destroyed
父 destroyed
10.高级特性
1.插槽
三种
匿名插槽
const UnnamedComponent = {
name: "UnnamedComponent",
methods: {},
template: `<slot>默认值</slot>`,
}
具名插槽
const NamedComponent = {
name: "NamedComponent",
template: `
<slot name="header"></slot>
<div>conent</div>
<slot name="footer"></slot>
`,
}
作用域插槽:父组件能够调用子组件的数据
const ScopeComponent = {
name: "ScopeComponent",
data() {
return {
list: ["a", "b", "c"],
}
},
template: `
<slot v-for="item in list" :item="item"/>
`,
}
//in app template
<div>
<unnamed-component>
<div>
我是插槽里的内容
{{count}}
</div>
</unnamed-component>
<unnamed-component></unnamed-component>
<named-component>
<template v-slot:header><div>header</div></template>
<template v-slot:footer><div>footer</div></template>
</named-component>
<scope-component v-slot="list">
<span>{{list.item}}</span>
</scope-component>
</div>`
2.动态、异步组件
动态组件是不确定要渲染的是什么组件,所以用component :is=“组件名”,先占个坑。
const OneComponent = {
neme: "OneCompontent",
template: `<div>我是OneComponent</div>`,
}
const TwoComponent = {
neme: "TwoCompontent",
template: `<div>我是TwoComponent</div>`,
}
const app = Vue.createApp({
components: { OneComponent, TwoComponent },
data() {
return {
currentItem: "one-component",
}
},
methods: {
handleClick() {
if (this.currentItem === "one-component") {
this.currentItem = "two-component"
} else {
this.currentItem = "one-component"
}
},
},
template: `
<component :is="currentItem"/>
<button @click="handleClick">切换</button>
`,
})
const vm = app.mount("#root")
可以使用keep-alive保留动态属性的内容
异步组件,引入的时候
compontents:{
asyncComponent:()=>{import("./组件的位置")}
}
3.$nectTick(组件更新后,如何获取最新的DOM)
在数据更新后,获得更新的DOM节点
给你想要监控的dom节点添加ref属性
<ul ref="ul">
进行数据更新操作(比如添加/删除一个li)后输出
this.$refs.url.childNodes
发现获取到的是操作前的dom节点
this.$nextTick(()=>{
使用 this.$refs.url.childNodes
})
就行了
4.keep-alive(缓存组件)
将组件用包裹,可以和动态组件配合使用。使组件不会重复渲染(重复执行mounted)
5.自定义v-model
<input v-model="inputVlue"/>
的本质其实是
<input
:value="inputValue"
@input/@change="inputValue=$event.target.value"/>
所以 父组件正常使用v-model
子组件
<input :value="inputValue"
@input="$emit('change',$event.target.value)"/>
//子组件内部
props:[inputValue],
model:{
prop:'inputValue',
event:'change'
}
6.mixin(抽离公共逻辑)
Composition API也可以实现
mixins:[组件名]
会将引入的组件的内容与当前组件的内容混合。
可以将公共逻辑抽离在另一个组件中,使用时引入就行。
缺点:命名冲突、多对多关系
7.vuex
状态管理
设置想要管理的值
store->index.js
state:{
name:'aaa'
}
在其他组件使用这个值
this.$store.state.name
修改这个值
//其他组件里
this.$store.dispatch("changeName",name)
//store->index.js里
actions: {
changeName(ctx,name) {
ctx.commit("handleChangeName", name)
}
},
mutations: {
handleChangeName(state, name) {
state.name = name
}
},
或者,跳过action
this.$store.commit("handleChangeName",name)