自定义组件使用 v-model
封装input 组件实现双向数据绑定
// 父组件
<template>
<h1>App 组件 ---- {{ value }}</h1>
<children v-model:value="value" />
</template>
<script setup>
import children from './components/children.vue'
import { ref } from 'vue'
const value = ref('张三')
</script>
// 子组件
<template>
<input type="text" :value="value" @input="changeEl">
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
defineProps(['value'])
const emit = defineEmits(['update:value'])
function changeEl(e) {
emit('update:value', e.target.value)
}
</script>
计算属性(computed)
在Vue 3的组合式API中,你可以使用computed函数来创建计算属性。computed函数接受一个函数作为参数,该函数返回计算属性的值。计算属性可以依赖于响应式数据,并且只有在依赖的响应式数据发生变化时才会重新计算。
<template>
<h1>APP 组件</h1>
<hr />
<h1>原价: {{ price }} <button @click="changePrice">修改原价</button></h1>
<h1>会员价: {{ vipPrice }} <button @click="changeVipPrice">修改会员价</button></h1>
<h1>超级会员价: {{ sVipPrice }}</h1>
</template>
<script setup>
import { ref, computed } from "vue";
const price = ref(1000);
// 最常见的 计算属性写法, 但是这种写法 不允许修改 计算属性的值
// const vipPrice = computed(() => {
// return price.value / 2;
// });
const vipPrice = computed({
get () {
return price.value / 2
},
set (val) {
// console.log('你想修改 计算属性, 修改的值: ', val)
price.value = val * 2
}
})
const sVipPrice = computed(() => {
return price.value * 0.1;
});
// 修改原价
function changePrice() {
price.value = 100;
}
// 修改 vip 价格
function changeVipPrice () {
// console.log(vipPrice)
vipPrice.value = 1000
}
</script>
侦听器(watch)
在Vue 3的组合式API中,watch
是一个函数,用于监视数据的变化并执行相应的操作。它可以替代Vue 2中的this.$watch
方法。
watch
函数接受两个参数:要监视的数据源和回调函数。当数据源发生变化时,回调函数将被触发。此外,还可以传递一些选项参数,如deep
用于深度监视对象内部的变化,immediate
用于立即执行回调函数等。
在使用watch
时,可以监视响应式数据、计算属性或ref
对象的变化,以及在监视回调函数中执行相应的逻辑,比如发送请求、更新UI等操作。
<template>
<h1>APP 组件</h1>
<hr />
<h1>原价: {{ price }} <button @click="price = 500">修改原价</button></h1>
<h1>会员价: {{ vipPrice }}</h1>
<button @click="appName = '李四'">修改名字: {{ appName }}</button>
<hr />
<ul>
<li>id: {{ obj.id }}</li>
<li>age: {{ obj.age }} <button @click="obj.age++">增加年龄</button></li>
</ul>
</template>
<script setup>
import { ref, watch, reactive } from "vue";
const price = ref(1000);
const vipPrice = ref(0);
const appName = ref("张三");
const obj = reactive({
id: "QF001",
age: 18,
});
// watch('侦听的值', '一个回调函数, 会在侦听的值发生变化的时候执行', '一个对象, 对当前侦听器的一些配置项')
// watch(price, () => {
// // console.log('此时 price 发生变化')
// vipPrice.value = price.value / 2
// }, { immediate: true })
/**
* 选项式开发中, 侦听器本身只能侦听一个值, 如果需要侦听多个值, 我们需要很多额外的操作
* 1. 在计算属性中, 返回一个对象, 对象内部是你需要监听的多个值
* 2. 在侦听器中添加一个对这个计算属性的监听, 并且需要开启 深层监听
*
* 但是组合式开发中, 如果 watch 需要侦听多个值, 我们只需要将第一个参数更换为一个数组
* 数组内, 书写你需要侦听的 数据
*/
watch([price, appName], () => {
console.log("当前侦听器会在 price/appName 的值发生变化的时候执行");
vipPrice.value = price.value / 2;
});
watch(obj, () => {
console.log("当前obj侦听器执行~~");
});
</script>
watchEffter
<template>
<h1>APP 组件</h1>
<hr />
<h1>原价: {{ price }} <button @click="price = 500">修改原价</button></h1>
<h1>会员价: {{ vipPrice }}</h1>
</template>
<script setup>
import { ref, watch, watchEffect } from "vue";
const price = ref(1000);
const vipPrice = ref(0);
// 当前侦听器会自动追踪内部书写的响应式数据(不包含赋值号左边的), 并且页面打开的时候会立即执行
watchEffect(() => {
vipPrice.value = price.value / 2;
})
// 侦听 price 响应式对象, 会在 页面一打开的时候和 price 发生变化的时候执行
// watch(
// price,
// () => {
// console.log("当前侦听器会在 price/appName 的值发生变化的时候执行");
// vipPrice.value = price.value / 2;
// },
// {
// immediate: true,
// }
// );
</script>
组合式API 的生命周期
<template>
<div></div>
</template>
<script setup>
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
} from "vue";
/**
* 在挂载开始之前被调用:相关的 render 函数首次被调用。
*/
onBeforeMount(() => {});
/**
* 组件挂载时调用
*/
onMounted(() => {});
/**
* 数据更新时调用,发生在虚拟 DOM 打补丁之前。
* 这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
*/
onBeforeUpdate(() => {});
/**
* 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子
*/
onUpdated(() => {});
/**
* 在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的
*/
onBeforeUnmount(() => {});
/**
* 卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,
* 所有事件侦听器都被移除,所有子组件实例被卸载
*/
onUnmounted(() => {});
</script>
组合式API 的路由
基本使用
<template>
<div>
<div>我是第一个页面</div>
<button @click="link2">跳转到第二个页面</button>
</div>
</template>
<script setup>
// 从vue-router引入 useRouter这个钩子
import { useRouter } from "vue-router";
// 初始化这个钩子并赋值给router
const router = useRouter();
// 跳转到页面2
const link2 = () => {
// 使用我们刚声明的router跳转
router.push("/v11");
};
页面传参
传值方式和 vue2.x 的路由一样,也是 query 和 params,但是接收参数的形式有所不同
// 传参页
<template>
<div>
<div>我是第一个页面</div>
<button @click="link2">跳转到第二个页面</button>
</div>
</template>
<script setup>
// 从vue-router引入 useRouter这个钩子
import { useRouter } from "vue-router";
// 初始化这个钩子并赋值给router
const router = useRouter();
// 跳转到页面2
const link2 = () => {
// 跳转你的时候传一个id为1
router.push("/v11?id=1");
};
</script>
// 接收页
<template>
<div>我是第二个页面</div>
</template>
<script setup>
import { useRoute } from "vue-router";
// 初始化useRoute并赋值给route
const route = useRoute();
// 获取query的参数
console.log(route.query);
</script>
组合式 API 获取 元素
<template>
<!-- 2. 通过 ref 属性, 将刚才创建的响应式数据绑定给 某一个标签/组件
(绑定的时候不需要添加 冒号) -->
<h1 ref="myh1">我是首页的内容</h1>
<!--
组合式 API 中 获取 标签/组件
1. 通过 ref 方法 创建一个响应式数据
2. 通过 ref 属性, 将刚才创建的响应式数据绑定给 某一个标签/组件
(绑定的时候不需要添加 冒号)
3. 在某一个合适的时机, 你需要访问标签的时候, 可以直接通过 响应式数据访问到
标签
-->
<button @click="getH1">获取标签</button>
</template>
<script setup>
import { ref } from 'vue'
// 1. 通过 ref 方法 创建一个响应式数据
const myh1 = ref(null)
function getH1() {
// 3. 在某一个合适的时机, 你需要访问标签的时候, 可以直接通过 响应式数据访问到标签
console.log('获取 h1 标签: ', myh1.value)
}
</script>