学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes
觉得有帮助的同学,可以点心心支持一下哈(笔记是根据b站上学习的尚硅谷的前端视频【张天禹老师】,记录一下学习笔记,用于自己复盘,有需要学习的可以去b站学习原版视频)
一、标签的 ref 属性
作用:用于注册模板引用。
- 用在普通DOM标签上,获取的是DOM节点。
- 用在组件标签上,获取的是组件实例对象。
子组件:
<template>
<div class="person">
<h1>尚硅谷</h1>
<h2 ref="title2">前端</h2>
<h3>Vue</h3>
<button @click="showLog">点我输出这个元素</button>
</div>
</template>
<!-- 子组件Person.vue中要使用defineExpose暴露内容 -->
<script lang="ts" setup name="Person">
import { ref, defineExpose } from 'vue'
// 数据
let title2 = ref()
let name = ref('张三')
let age = ref(18)
/****************************/
/****************************/
function showLog () {
console.log(title2.value)
}
// 使用defineExpose将组件中的数据交给外部
defineExpose({ name, age })
</script>
<style>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0px 5px;
}
</style>
父组件:
<!-- 父组件App.vue -->
<template>
<Person ref="ren" />
<button @click="test">测试</button>
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import { ref } from 'vue'
let ren = ref()
function test () {
console.log(ren.value)
// console.log(ren.value.name)
// console.log(ren.value.age)
}
</script>
二、props
父组件传递值给子组件
// 定义一个接口,限制每个Person对象的格式
export interface PersonInter {
id:string,
name:string,
age:number
}
// 定义一个自定义类型Persons
export type Persons = Array<PersonInter>
App.vue中代码:
<template>
<Person :list="persons"/>
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import {reactive} from 'vue'
import {type Persons} from './types'
let persons = reactive<Persons>([
{id:'e98219e12',name:'张三',age:18},
{id:'e98219e13',name:'李四',age:19},
{id:'e98219e14',name:'王五',age:20}
])
</script>
Person.vue中代码:
<template>
<div class="person">
<ul>
<li v-for="item in list" :key="item.id">
{{item.name}}--{{item.age}}
</li>
</ul>
</div>
</template>
<script lang="ts" setup name="Person">
import {defineProps} from 'vue'
import {type PersonInter} from '@/types'
// 第一种写法:仅接收
// const props = defineProps(['list'])
// 第二种写法:接收+限制类型
// defineProps<{list:Persons}>()
// 第三种写法:接收+限制类型+指定默认值+限制必要性
let props = withDefaults(defineProps<{list?:Persons}>(),{
list:()=>[{id:'asdasg01',name:'小猪佩奇',age:18}]
})
console.log(props)
</script>
三、生命周期
解析流程:index.html=>main.ts=>person(子组件)=>app(父组件) 【先解析子组件再父组件】
- 概念:Vue组件实例在创建时要经历一系列的初始化步骤,在此过程中Vue会在合适的时机,调用特定的函数,从而让开发者有机会在特定阶段运行自己的代码,这些特定的函数统称为:生命周期钩子
- 规律:生命周期整体分为四个阶段,分别是:创建、挂载、更新、销毁,每个阶段都有两个钩子,一前一后。
Vue2的生命周期
创建阶段:beforeCreate、created挂载阶段:beforeMount、mounted更新阶段:beforeUpdate、updated销毁阶段:beforeDestroy、destroyed
- 实例代码:
子组件
<template>
<div class="person">
<h2>当前求和为:{{ sum }}</h2>
<button @click="add">点我sum+1</button>
</div>
</template>
<script>
export default {
/* eslint-disable */
name: 'Person',
// 数据
data() {
return {
sum: 1
}
},
// 方法
methods: {
add() {
this.sum += 1
}
},
// 创建前
beforeCreate() {
console.log('创建前')
},
// 创建完毕
created() {
console.log('创建完毕')
},
// 挂载前
beforeMount() {
console.log('挂载前')
},
// 挂载完毕
mounted() {
console.log('挂载完毕')
},
// 更新前
beforeUpdate() {
console.log('更新前')
},
// 更新完毕
updated() {
console.log('更新完毕')
},
// 销毁前
beforeDestroy() {
console.log('销毁前')
},
// 销毁完毕
destroyed() {
console.log('销毁完毕')
}
}
</script>
父组件:
<template>
<div id="app"><Person v-if="isshow" /></div>
</template>
<script>
import Person from './components/Person.vue'
export default {
name: 'App',
components: {
Person
},
data () {
return {
isshow: true
}
}
}
</script>
Vue3的生命周期
创建阶段:setup挂载阶段:onBeforeMount、onMounted更新阶段:onBeforeUpdate、onUpdated卸载阶段:onBeforeUnmount、onUnmounted
- 常用的钩子:onMounted(挂载完毕)、onUpdated(更新完毕)、onBeforeUnmount(卸载之前)
- 示例代码:
子组件:
<template>
<div class="person">
<h2>当前求和为:{{ sum }}</h2>
<button @click="changeSum">点我sum+1</button>
</div>
</template>
<!-- vue3写法 -->
<script lang="ts" setup name="Person">
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
// 数据
let sum = ref(0)
// 方法
function changeSum () {
sum.value += 1
}
console.log('setup')
// 生命周期钩子
onBeforeMount(() => {
console.log('挂载之前')
})
onMounted(() => {
console.log('子---挂载完毕')
})
onBeforeUpdate(() => {
console.log('更新之前')
})
onUpdated(() => {
console.log('更新完毕')
})
onBeforeUnmount(() => {
console.log('卸载之前')
})
onUnmounted(() => {
console.log('卸载完毕')
})
</script>
父组件:
<template>
<Person v-if="isShow" />
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import { ref, onMounted } from 'vue'
let isShow = ref(true)
onMounted(() => {
console.log('父---挂载完毕')
})
</script>
四、自定义hook
- 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装,类似于vue2.x中的mixin。
- 自定义hook的优势:复用代码, 让setup中的逻辑更清楚易懂。
示例代码:
- useSum.ts中内容如下:
import { ref, onMounted } from "vue";
export default function () {
let sum = ref(0);
const increment = () => {
sum.value += 1;
};
const decrement = () => {
sum.value -= 1;
};
onMounted(() => {
increment();
});
//向外部暴露数据
return { sum, increment, decrement };
}
- useDog.ts中内容如下:
import { reactive, onMounted } from "vue";
import axios, { AxiosError } from "axios";
export default function () {
let dogList = reactive<string[]>([]);
// 方法
async function getDog() {
try {
// 发请求
let { data } = await axios.get(
"https://dog.ceo/api/breed/pembroke/images/random"
);
// 维护数据
dogList.push(data.message);
} catch (error) {
// 处理错误
const err = <AxiosError>error;
console.log(err.message);
}
}
// 挂载钩子
onMounted(() => {
getDog();
});
//向外部暴露数据
return { dogList, getDog };
}
- 组件中具体使用:
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="increment">点我+1</button>
<button @click="decrement">点我-1</button>
<hr />
<img v-for="(u, index) in dogList" :key="index" :src="u" />
<br />
<button @click="getDog">再来一只狗</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'App'
})
</script>
<script setup lang="ts">
import useSum from '../hooks/useSum'
import useDog from '../hooks/useDog'
let { sum, increment, decrement } = useSum()
let { dogList, getDog } = useDog()
</script>
<style>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0px 5px;
}
</style>