前端 Vue3 框架 | 地址 |
---|---|
(一)基础语法 | https://blog.csdn.net/weixin_42771853/article/details/129956268 |
(二)组件化基础 | https://blog.csdn.net/weixin_42771853/article/details/129957080 |
(三)Composition API | https://blog.csdn.net/weixin_42771853/article/details/129957511 |
(四)Vue3 全家桶 router、vuex、pinia、axios | https://blog.csdn.net/weixin_42771853/article/details/129957595 |
setup 函数可以替代之前所编写的大部分其他选项:比如methods、computed、watch、data、生命周期等等
props
:父组件传递过来的属性会被放到props对象中,我们在setup中如果需要使用,那么就可以直接 通过props参数获取
context
:里面包含三个属性
setup的返回值可以在模板template中被使用
在setup被调用之前,data、computed、methods等都没有被解析,this并没有指向当前组件实例
使用reactive的函数,可以使setup中定义的数据(多为复杂类型)提供响应式的特性。
reactive API对传入的类型是有限制的,它要求我们必须传入的是一个对象或者数组类型
对reactive返回的对象进行解构获取值,那么之后无论是修改结构后的变量,还是修改reactive 返回的state对象,数据都不再是响应式的:
<template>
<div>
<h2>info: {{ name }} - {{ age }} - {{ height }}</h2>
<button @click="age++">修改age</button>
<button @click="height = 1.89">修改height</button>
</div>
</template>
<script>
import { reactive, toRefs, toRef } from 'vue'
export default {
setup() {
const info = reactive({
name: "why",
age: 18,
height: 1.88
})
// reactive被解构后会变成普通的值, 失去响应式,需要使用toRef(s)
const { name, age } = toRefs(info)
const height = toRef(info, "height")
return {
name,
age,
height
}
}
}
</script>
ref 会返回一个可变的响应式对象,该对象作为一个响应式的引用维护着它内部的值,这就是ref名称的来源
注意:
<template>
<div>
<h2>message: {{ message }}</h2>
<button @click="changeMessage">修改message</button>
<hr>
<h2>账号: {{ account.username }}</h2>
<h2>密码: {{ account.password }}</h2>
<button @click="changeAccount">修改账号</button>
<hr>
<!-- 默认情况下在template中使用ref时, vue会自动对其进行解包(取出其中value) -->
<h2>当前计数: {{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="counter++">+1</button>
<hr>
<!-- 使用的时候需要写.value -->
<h2>当前计数: {{ info.counter.value }}</h2>
<!-- 修改的时候不需要写.value -->
<h2>当前计数: {{ info1.counter }}</h2>
</div>
</template>
<script>
import { reactive, ref } from 'vue'
export default {
setup() {
// 1.定义普通的数据: 可以正常的被使用
// 缺点: 数据不是响应式的
let message = "Hello World"
function changeMessage() {
message = "你好啊,李银河!" // 页面上的 message 不会更改
console.log(message)
}
// 2.定义响应式数据
// 2.1.reactive函数: 定义复杂类型的数据
const account = reactive({
username: "coderwhy",
password: "123456"
})
function changeAccount() {
account.username = "kobe"
}
// 2.2.ref函数: 定义简单类型的数据(也可以定义复杂类型的数据)
// counter定义响应式数据
const counter = ref(0)
function increment() {
counter.value++
}
// 3.ref是浅层解包
const info = {
counter
}
const info1 = reactive({
counter
})
return {
message,
changeMessage,
account,
changeAccount,
counter,
increment,
info
}
}
}
</script>
<template>
<div>
<form>
账号: <input type="text" v-model="account.username">
密码: <input type="password" v-model="account.password">
</form>
<show-info :name="name" :age="age"></show-info>
</div>
</template>
<script>
import { onMounted, reactive, ref } from 'vue'
import ShowInfo from './ShowInfo.vue'
export default {
components: {
ShowInfo
},
data() {
return {
message: "Hello World"
}
},
setup() {
// 定义响应式数据: reactive/ref
// 强调: ref也可以定义复杂的数据
const info = ref({})
console.log(info.value)
// 1.reactive的应用场景
// 1.1.条件一: reactive应用于本地的数据
// 1.2.条件二: 多个数据之间是有关系/联系(聚合的数据, 组织在一起会有特定的作用)
const account = reactive({
username: "coderwhy",
password: "1234567"
})
// 2.ref的应用场景: 其他的场景基本都用ref(computed)
// 2.1.定义本地的一些简单数据
const name = ref("why")
const age = ref(18)
// 2.定义从网络中获取的数据也是使用ref
// const musics = reactive([])
const musics = ref([])
onMounted(() => {
const serverMusics = ["海阔天空", "小苹果", "野狼"]
musics.value = serverMusics
})
return {
account,
name,
age
}
}
}
</script>
我们传入给其他地方(组件)的这个响应式对象希望在另外一个地方(组件)被使用,但是不能被修改
常见的readonly方法会传入三个类型的参数:
规则:
// App.vue
<template>
<h2>App: {{ info }}</h2>
<show-info
:roInfo="roInfo"
@changeRoInfoName="changeRoInfoName">
</show-info>
</template>
<script>
import { reactive, readonly } from 'vue'
import ShowInfo from './ShowInfo.vue'
export default {
components: {
ShowInfo
},
setup() {
// 本地定义多个数据, 都需要传递给子组件
// name/age/height
const info = reactive({
name: "why",
age: 18,
height: 1.88
})
// 使用readOnly包裹info
const roInfo = readonly(info)
function changeRoInfoName(payload) {
info.name = payload
}
return {
roInfo,
changeRoInfoName
}
}
}
</script>
// ShowInfo.vue
<template>
<div>
<!-- 想修改info中内容的正确做法: 符合单项数据流-->
<!-- 使用readonly的数据 -->
<h2>ShowInfo: {{ roInfo }}</h2>
<!-- 代码就会无效(报警告) -->
<!-- <button @click="roInfo.name = 'james'">ShowInfo按钮</button> -->
<button @click="roInfoBtnClick">roInfo按钮</button>
</div>
</template>
<script>
export default {
props: {
// reactive数据
info: {
type: Object,
default: () => ({})
},
// readonly数据
roInfo: {
type: Object,
default: () => ({})
}
},
emits: ["changeRoInfoName"],
setup(props, context) {
function roInfoBtnClick() {
context.emit("changeRoInfoName", "james")
}
return {
roInfoBtnClick
}
}
}
</script>
可以在 setup 函数中使用 computed 方法来编写一个计算属性:
<template>
<h2>{{ fullname }}</h2>
<button @click="setFullname">设置fullname</button>
<h2>{{ scoreLevel }}</h2>
</template>
<script>
import { reactive, computed, ref } from "vue";
export default {
// 原Options API写法
// computed: {
// fullname() {
// return this.firstName + this.lastName;
// },
// },
setup() {
// 1.定义fullname
const names = reactive({
firstName: "kobe",
lastName: "bryant",
});
// 方法一
// const fullname = computed(() => {
// return names.firstName + " " + names.lastName
// })
// 方法二
const fullname = computed({
set: function (newValue) {
const tempNames = newValue.split(" ");
names.firstName = tempNames[0];
names.lastName = tempNames[1];
},
get: function () {
return names.firstName + " " + names.lastName;
},
});
function setFullname() {
fullname.value = "coder why";
console.log(names);
} // 此时可以更改数据
// 2.定义score
const score = ref(89);
const scoreLevel = computed(() => {
return score.value >= 60 ? "及格" : "不及格"});
return {
names,
fullname,
setFullname,
scoreLevel,
};
},
};
</script>
定义一个ref对象,绑定到元素或者组件的ref属性上即可
<template>
<!-- 1.获取元素 -->
<h2 ref="titleRef">我是标题</h2>
<button ref="btnRef">按钮</button>
<!-- 2.获取组件实例 -->
<show-info ref="showInfoRef"></show-info>
</template>
<script>
import { ref, onMounted } from 'vue'
import ShowInfo from './ShowInfo.vue'
export default {
components: {
ShowInfo
},
setup() {
const titleRef = ref()
const btnRef = ref()
const showInfoRef = ref()
// mounted的生命周期函数
onMounted(() => {
console.log(titleRef.value)
console.log(btnRef.value)
console.log(showInfoRef.value)
// 取ShowInfo.vue中的函数
showInfoRef.value.showInfoFoo()
})
return {
titleRef,
btnRef,
showInfoRef
}
}
}
</script>
使用直接导入的 onX 函数注册生命周期钩子,beforeCreate
、created
不再需要了
<template>
<div>AppContent</div>
</template>
<script>
import { onMounted, onUpdated, onUnmounted } from 'vue'
export default {
// beforeCreate() {
// },
// created() {
// },
// beforeMount() {
// },
// mounted() {
// },
// beforeUpdate() {
// },
// updated() {
// }
setup() {
// 在执行setup函数的过程中, 你需要注册别的生命周期函数
onMounted(() => {
console.log("onmounted")
})
}
}
</script>
通过 provide 方法来定义每个 Property,可以传入两个参数:
通过 inject 来注入需要的属性和对应的值,可以传入两个参数:
// App.vue
<template>
<div>AppContent: {{ name }}</div>
<button @click="name = 'kobe'">app btn</button>
<show-info></show-info>
</template>
<script>
import { provide, ref } from 'vue'
import ShowInfo from './ShowInfo.vue'
export default {
components: {
ShowInfo
},
setup() {
const name = ref("why")
provide("name", name)
provide("age", 18)
return {
name
}
}
}
</script>
// ShowInfo.vue
<template>
<div>ShowInfo: {{ name }}-{{ age }}-{{ height }} </div>
</template>
<script>
import { inject } from 'vue'
export default {
// inject的options api注入, 那么依然需要手动来解包
// inject: ["name", "age"],
setup() {
const name = inject("name")
const age = inject("age")
const height = inject("height", 1.88)
return {
name,
age,
height
}
}
}
</script>
可以通过watch选项来侦听data或者props的数据变化,当数据变化时执行某一些操作
<template>
<div>AppContent</div>
<button @click="message = '你好啊,李银河!'">修改message</button>
<button @click="info.friend.name = 'james'">修改info</button>
</template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
setup() {
// 1.定义数据
const message = ref("Hello World")
const message2 = ref("Hello World2")
const info = reactive({
name: "why",
age: 18,
friend: {
name: "kobe"
}
})
// 2.侦听数据的变化
watch(message, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
watch(info, (newValue, oldValue) => {
console.log(newValue, oldValue)
console.log(newValue === oldValue)
}, {
immediate: true
})
// 3.监听reactive数据变化后, 获取普通对象
watch(() => ({ ...info }), (newValue, oldValue) => {
console.log(newValue, oldValue)
}, {
immediate: true,
deep: true
})
// 侦听多个数据源
watch([message, message2], (newValue, oldValue) => {
console.log(newValue, oldValue)
})
return {
message,
message2,
info
}
}
}
</script>
<template>
<div>
<h2>当前计数: {{ counter }}</h2>
<button @click="counter++">+1</button>
<button @click="name = 'kobe'">修改name</button>
</div>
</template>
<script>
import { watchEffect, watch, ref } from 'vue'
export default {
setup() {
const counter = ref(0)
const name = ref("why")
// watch(counter, (newValue, oldValue) => {})
// 1.watchEffect传入的函数默认会直接被执行
// 2.在执行的过程中, 会自动的收集依赖(依赖哪些响应式的数据)
const stopWatch = watchEffect(() => {
console.log("-------", counter.value, name.value)
// 判断counter.value > 10,停止侦听
if (counter.value >= 10) {
stopWatch()
}
})
return {
counter,
name
}
}
}
</script>
对counter逻辑进行抽取:
修改title的Hook:
监听界面滚动位置的Hook:
的时候,任何在
声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板template中直接使用defineProps
和 defineEmits
API
中。通过defineExpose
解决// App.vue
<template>
<div>AppContent: {{ message }}</div>
<button @click="changeMessage">修改message</button>
<show-info name="why"
:age="18"
@info-btn-click="infoBtnClick"
ref="showInfoRef">
</show-info>
</template>
<script setup>
// 1.所有编写在顶层中的代码, 都是默认暴露给template可以使用
import { ref, onMounted } from 'vue'
import ShowInfo from './ShowInfo.vue'
// 2.定义响应式数据
const message = ref("Hello World")
console.log(message.value)
// 3.定义绑定的函数
function changeMessage() {
message.value = "你好啊, 李银河!"
}
function infoBtnClick(payload) {
console.log("监听到showInfo内部的点击:", payload)
}
// 4.获取组件实例
const showInfoRef = ref()
onMounted(() => {
showInfoRef.value.foo()
})
</script>
// ShowInfo.vue
<template>
<div>ShowInfo: {{ name }}-{{ age }}</div>
<button @click="showInfoBtnClick">showInfoButton</button>
</template>
<script setup>
// 定义props
const props = defineProps({
name: {
type: String,
default: "默认值"
},
age: {
type: Number,
default: 0
}
})
// 绑定函数, 并且发出事件
const emits = defineEmits(["infoBtnClick"])
function showInfoBtnClick() {
emits("infoBtnClick", "showInfo内部发生了点击")
}
// 定义foo的函数
function foo() {
console.log("foo function")
}
// 函数可公开
defineExpose({
foo
})
</script>