v-if,v-show
- v-show 都会渲染,通过display:none控制显示/隐藏 -- 适合频繁切换使用
- v-if 不符合直接不渲染,更高的切换开销,切换时子组件会销毁重建 -- 渲染后很少改变使用
事件修饰符
执行事件时进行了一些封装
- @keyup.enter="fn" 回车键执行
相当于
fn(){
if(e.key === 'Enter'){
执行内容...
}
}
- .prevent阻止默认事件 .stop阻止冒泡 @click.prevent="clickHandle"
- v-model.trim
数组变化监听
- 调用可以改变原数组的方法,会实时更新数据
- push, pop, shift, unshift, splice, sort, reverse
this.data.push(...)
- 其他方法则需要重新赋值
this.data = this.data.concact(...)
计算属性
基于现有数据,计算出来的新属性,依赖数据变化,自动重新计算
computed: {
itContent() {
return this.data.content.length > 0 ? "ya" : "nu";
必须return一个结果
},
},
使用 {{ itContent }}--本质还是属性,不需要加括号
计算属性 对比 方法
定义函数方法也可以实现类似功能,
- 计算属性 缓存特性--依赖值不变时,只会执行一次,页面多个地方使用计算属性,也只会执行一次
- methods方法 则是调用一次就会执行一次,无论依赖值是否改变
计算属性修改
- 获取值 {{ fullname }},执行get中的内容
- 修改值 this.fullname = ...,执行set中的内容
computed: {
fullname: {
get() {
return this.firstName + this.lastName;
},
set(value) {
this.firstName = value.slice(0, 1);
this.lastName = value.slice(1);
},
},
},
class样式绑定
可以接受数组/对象
<h3 :class="classObject">class样式绑定</h3>
<h3 :class="[arrActive, arrDanger]"></h3>
data(){
return{
classObject: {
active: true,
danger: true,
},
arrActive: active
arrDanger: danger
}
}
组件样式 scoped
< style scoped>,样式只作用于当前组件
- 原理,标签加上 data-v-hash的属性,css选择器也会被添加[data-v-hash]的属性选择器
watch 监听器
监听到数据变化的过程,
- 数据发生变化,自动执行的函数
- 函数名和监听的数据对象名一致
- 简单类型数据
<p>{{ message }}</p>
----------
export default {
data() {
return {
message: "hello", 数据
};
},
watch: { 监听
message(newValue, oldValue) {
console.log("oldvalue:", oldValue, "--newvalue", newValue);
},
},
};
- 深度监听 立即执行
data(){
return{
obj:{ words:'', lang:'' }
}
}
watch:{
obj:{
deep: true, // 复杂类型
immediate: true, //立即执行一次
handler(newValue){}
}
}
表单输入绑定 v-model
表单的数据可以实时获取到
<form>
<input v-model="message" type="text" />
</form>
<p>{{ message }}</p>
data() {
return {
message: "",
};
},
- v-model.lazy惰性,不实时,失焦/回车才获取数据
- v-model.trim, v-model.number
直接访问底层DOM - ref
vue抽象了大部分操作
- 内容 {{}},属性v-bind: , 事件@
- 查找范围,当前组件
<h3 ref="container">容器</h3>
<button @click="getElement">获取元素</button>
methods: {
getElement() {
console.log(this.$refs.container); 打印<h3>hahahah</h3>
this.$refs.container.innerHTML = "hahahah";
},
},
组件引入方式
- 局部注册 - 某个组件内部引入显示
<script>
import FormDemo from "./components/FormDemo.vue"; --1.引入组件
export default { --2.注入组件
components: { FormDemo },
};
</script>
<template>
<FormDemo /> --3.显示组件
</template>
---------------------
<script setup> 设置了setup可以省略第2步
- 全局注册 - 最外层注册一次,哪里都可以引入
- 不方便打包,无法自动移除
组件传递数据 - 父传子
- props可以接受任何类型数据 父组件
<Child title="props title" :info="message" />
-------info为动态值
data() {
return {
message: "动态传递数据",
};
},
子组件
export default {
data() {
return;
},
props: ["title", "message"],
};
props校验
类型,默认值,必传标识
props: {
title: { 接受传入props title
type: [String, Number], ----类型限制
default: "aaa", ----默认值
required: true,
validator(value){ //自定义校验
if(){ return true }
else{ return false }
}
},
},
自定义事件 - 子传父
子组件可以调用父组件的事件 父组件
<Child @someEvent="getHandle" />
--------------------
methods: {
getHandle(data) {
this.message = data;
},
},
子组件
<button @click="clickEvent">传递数据</button>
------------------------------
methods: {
clickEvent() {
this.$emit("someEvent", "child数据");
-- someEvent定义在子组件上的事件
},
},
v-model原理
v-model是一个语法糖,input上就是value属性和input事件合写
<input v-model="msg" />
<input :value="msg" @input="msg = $event.target.value" />
v-model表单组件类封装
<InputCom v-model="text" />
// <InputCom :value="text" @input="text=$event.target.value" />
-------
<input :value="value" @change="handleChange" />
export default{
props:['value'],
methods:{
handleChange(e){
this.$emit('input', e.target.value)
}
}
}
自定义指令
自定义指令,封装dom操作
元素加载自动获得焦点
mounted(){
this.$refs.inp.focus()
}
--------------
directives:{
'focus':{
inserted(el){ inserted: 指令所在元素插入到页面中时触发;el:指令绑定的元素
el.focus()
}
}
}
<input v-focus>
组件自定义事件和v-model
v-model可以实时获取到form表单输入的内容,现在想在另一个组件中显示对应的内容
- 表单组件
<input type="text" v-model="search" /> ----input输入框
<script>
export default {
data() {
return {
search: "",
};
},
watch: { -------状态修改监听
search(newValue, oldValue) {
this.$emit("searchEvent", newValue); ----调用组件自定义事件啊
},
},
};
</script>
- 获取输入内容的组件
<Search @searchEvent="handleS" />
export default {
data() {
return {
message: "",
};
},
methods: {
handleS(data) {
this.message = data;
},
},
};
</script>
插槽
组件内的结构,支持自定义
- < slot>元素,是一个插槽出口,表示父元素提供的内容在哪里渲染
- 插槽内容可以访问到父组件的作用域,因为插槽内容本身在父组件中定义
- 具名插槽 - 父元素渲染多块内容在子元素中 父元素:template v-slot:Header / #Header分别标识不同内容
<template>
<SlotsBase>
<template v-slot:Header> -------第一块内容
<div>
<h3>插槽标题</h3>
</div>
</template>
<template #main> ---------第二块内容
<div>
<h3>插槽内容</h3>
</div>
</template>
</SlotsBase>
</template>
子元素
<template>
<slot name="Header"></slot> ---引用展示
<hr />
<slot name="main"></slot>
</template>
- 插槽传值 - 使用子元素的值 子元素传值
<slot :msg="message"></slot>
父元素获取
<SlotsBase v-slot="slotProps"> ---子组件上添加v-slot属性
{{ slotProps.msg }}
具名插槽传值
<template>
<SlotsBase>
<template #Header="slotProps"> -------对应模板上添加
<div>
<h3>插槽标题</h3>
</div>
</template>
</SlotsBase>
</template>
生命周期
生命周期函数,自动执行
- 创建期 beforeCreate created --组件创建完成,但还没有显示
- 挂载期 beforeMount mounted
- 更新期 beforeUpdate updated
- 销毁期 beforeUnmount unMounted
应用
- ref获取DOM结构 mounted(){ 挂载后获取 }
- created() 可以发送初始化渲染请求,可以this.数据 = ...
- mounted(){ 页面结构已加载,可以操作dom (请求获取数据)}
动态组件
两个组件切换展示
<component :is="tabCom"></component>
--------------
data(){
return{
tabCom:'ComponentA' --赋值为字符串形式,引入的组件名称
}
},
methods:{
change(){
this.tabCom = this.tabCom == 'ComponentA' ? 'ComponentB' : 'ComponentA'
}
}
组件保持存活
< keep-alive>包裹组件< /keep-alive>
异步组件
在需要展示的时候才加载
const ComB = defineAsyncComponent(() => import("./components/ComB.vue"));
跨层级传递数据
根组件向嵌套多层的子组件传递数据,不需props层层传递
- provide inject
------根组件
provide(){
return {
message: this.message
}
}
------子组件
inject:["message"]
Vue从哪里开始
- 一个vue项目中,有且只有一个vue的实例对象
- 传入createApp()的参数是一个组件,“根组件”
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App); ---app: vue的实例对象
app.mount('#app')