API基础
涵盖了以下方面的 API:
● `响应式 API:例如 ref() 和 reactive(),使我们可以直接创建响应式状态、计算属性和侦听器`
● `生命周期钩子:例如 onMounted() 和 onUnmounted(),使我们可以在组件各个生命周期阶段添加逻辑`
● `依赖注入:例如 provide() 和 inject(),使我们可以在使用响应式 API 时,利用 Vue 的依赖注入系统`
组合式优点:
1.更好的逻辑复用,组合式 API 解决了 mixins 的所有缺陷
2.更灵活的代码组织
3.更好的类型推荐
4.更小的生产包体积
组合式两种写法
setup函数和重要知识
1.在vue3组合式中不需要写data,在setup中返回的对象就是data数据
2.在setup()中不能使用this,因此不能使用this.$props this.$attrs
3.vue3组合式中有两种变量定义
`ref 当赋值发生改变时,会进行更新`
`reactive 主要用于定义引用类型`,和ref不同的地方在于,`改变引用地址将与原绑定内容分离,不会更新改变`
`setup()`
4.setup() 函数中有两个参数
1) 函数的第一个参数是组件的 props
2) 函数的第二个参数是一个 Setup 上下文对象
其中包括 ttrs、emits、slots、expose
5.defineProps
defineProps返回的props对象,是一个proxy对象,所有特性和reactive基本相同,只不过`由defineProps定义出的props对象的值是只读的`,还有在模板上可以单独属性直接使用
对于数据
写法1
`在script中使用 setup()函数`
<template>
<div>
<div>{{ count }}</div>
<ul>
<li v-for="(value, index) in list" :key="index">{{ value }}</li>
</ul>
<button @click="clickHandler">按钮</button>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
props: ["a"],
setup(props, minxi) {
console.log(props);
console.log(minxi);
const count = ref(1);
const list = ref({ a: 1, b: 2 })
return {
count,
list
}
},
methods: {
clickHandler() {
this.count++
`值是数组类型`
this.list = [4, 5, 6]
this.list.length = 0;
this.list.push(...[4, 5, 6])
this.list.push(10)
`值是对象类型`
this.list = { c: 3, d: 4 }
this.list.c = 30;
Object.keys(this.list).forEach(key => delete this.list[key]);
Object.assign(this.list, { c: 3, d: 4 })
}
}
}
</script>
写法2
`在script标签中加 setup`
<template>
<div>
<div>{{ count }}</div>
<ul>
<li v-for="(value, index) in arr" :key="index">{{ value }}</li>
</ul>
<button @click="clickHandler">按钮</button>
</div>
</template>
<script setup>
import { reactive, ref, defineProps } from "vue";
const count = ref(1);
const arr=ref([1,2,3]);
defineProps(['a']);
function clickHandler() {
count.value++,
list.push(10),
list.length = 0;
list.push(...[4, 5, 6])
arr.value.push(4, 5)
console.log(arr)
}
</script>
对于事件和函数
写法1
<template>
<div>
<SecondView :count="count" ref="sv" @change="(value)=>console.log(value)"></SecondView>
<button @click="count++">按钮</button>
</div>
</template>
<script>
import SecondView from "@/views/SecondView.vue"
export default {
name: 'App',
components: {
SecondView
},
data() {
return {
count: 1,
total: 1
}
},
mounted(){
console.log(this.$refs.sv.name);
this.$refs.sv.changeName();
}
}
</script>
<template>
<div>
{{ count }}--{{ sum }}
<!-- {{ count }}--{{ props1 }} -->
<!-- <button @click="clickHandler">按钮1</button> -->
</div>
</template>
<script>
import { ref, toRef, toRefs, onMounted } from "vue"
export default {
name: "SecondView",
props: ["count"],
setup(props, context) {
const sum = toRef(props, "count")
const props1 = toRefs(props)
const name = ref("谢天")
const changeName = () => {
name.value = "张三"
}
context.expose({
name,
changeName
})
return {
sum,
props1
}
}
}
</script>
写法2
`1.defineEmits 定义事件
2.defineProps 获取父组件传来的值
3.defineModel v-model 的使用
4.defineExpose 把值暴露给父级
`
<SecondView :count="count" @change="(value) => console.log(value)" ref="sv" v-model="total" />
<button @click="count++">按钮2</button>
{{ total }}
mounted() {
console.log(this.$refs.sv.name);
this.$refs.sv.change()
}
<template>
<div>
{{ count }}--{{ sum }}
{{ count }}--{{ props1 }}
<button @click="clickHandler">按钮1</button>
</div>
</template>
<script setup>
import { defineEmits,defineProps,toRef,toRefs,defineExpose,ref } from "vue"
const emits=defineEmits(["change"])
const props=defineProps(["count"])
const modelValue=defineModel({required:true})
const name=ref("xietian")
defineExpose({name})
const sum=toRef(props,"count")
function clickHandler(){
emits("change",1)
modelValue.value++
}
</script>
响应式核心
ref()和reactive()
`ref 当赋值发生改变时,会进行更新`
`reactive 主要用于定义引用类型`,和ref不同的地方在于,`改变引用地址将与原绑定内容分离,不会更新改变`
1.要求 ref用来定义非引用类型 reactive用来定义引用类型
2.ref也可以设置引用类型,这时候,value值就会变成使用reactive定义Proxy对象了
3.reactive不能设置非引用类型
4.reactive 不能设置为null类型,ref 可以设置为null类型
6.`在<script steup> 写法中`
所有使用ref定义的,修改值都需要使用这个变量的value值修改
count.value++,
所有使用reactive定义的,直接修改其值就行了
`使用`
const list = ref([1, 2, 3, 4])
const list = ref({ a: 1, b: 2 })
const obj = reactive({ a: 1, b: 2 })
const obj = reactive([1, 2, 3])
`值是数组类型`
this.list = [4, 5, 6]
this.list.length = 0;
this.list.push(...[4, 5, 6])
this.list.push(10)
`值是对象类型`
this.list.c = 30;
this.list = { c: 3, d: 4 }
Object.keys(this.list).forEach(key => delete this.list[key]);
Object.assign(this.list, { c: 3, d: 4 })
`深层`
list.value={a:1,b:2,c:{d:4}}
list.value.c=10
console.log(list);
obj.value={a:1,b:2,c:{d:4}}
obj.value.c.d=10
console.log(obj);
useAttrs()
<ChildB :count="count" a="10"/>
<p>{{ attrs.a }}</p>
const attrs = useAttrs()
console.log(attrs)
computed ()
`使用`
<input type="text" v-model="msg">
<div>{{ message }}</div>
const msg = ref("")
const message = computed(() => {
return "小波说:" + msg.value
})
<input type="text" v-model="a">
<div>{{ s }}</div>
<button @click="clickHandler">按钮</button>
const a = ref("");
const s = computed({
ser(value) {
a.value = value.replace("---", "")
},
get() {
return a.value + "???"
}
})
function clickHandler() {
console.log(s);
}
readonly()
const ab = readonly({ a: 1, b: 20 })
ab.a = 10
var obj = { a: 1, b: 2 }
const ab = readonly(new Map(Object.entries(obj)))
ab.set("a", 10)
watch()
`参数列表:`
参数1为需要监听的响应式对象(可以是单个对象,也可以是一个数组,也可以是一个getter函数),
参数2为监听对象发生变化时所执行的回调
参数3是一些配置项:immediate是否开启立即监听,deep是否开启深度监听,flush回调的触发时机,onTrack / onTrigger用于调试的两个函数
`使用`
const obj = reactive({ a: 1, b: 2 })
watch(obj, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
setTimeout(() => {
obj.a=10
}, 1000);
const obj = reactive({ a: 1, b: 2 })
watch(() => obj.b, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
setTimeout(() => {
obj.b=10
}, 3000);
const a = ref(1)
watch(a, (value) => {
console.log(value)
})
setTimeout(() => {
a.value=100
}, 3000);
const a = ref(0)
const b = ref("a")
watch([a, b], ([newValue_a, newValue_b], [oldValue_a, oldValue_b]) => {
console.log(newValue_a, newValue_b);
console.log(oldValue_a, oldValue_b)
})
setTimeout(() => {
a.value = 100;
b.value = "abc"
}, 3000);
watch(obj, (newValue, oldValue) => {
console.log(newValue)
})
setTimeout(() => {
obj.b.c = 100
}, 3000);
watch(() => obj.b, (newValue, oldValue) => {
console.log(newValue)
}, {
`deep: true`
})
setTimeout(() => {
obj.b.c = 100
}, 3000);
watchEffect()
第一个参数就是要运行的副作用函数。`这个副作用函数的参数也是一个函数,用来注册清理回调`。`清理回调会在该副作用下一次执行前被调用`,可以用来清理无效的副作用
const count = ref(0)
watchEffect(() => {
console.log(count)
})
setTimeout(() => {
count.value = 10;
}, 3000)
const count = ref(0);
watchEffect((fn) => {
console.log("bbb");
var id = setTimeout(() => {
count.value = 10;
console.log("ccc")
}, 3000);
fn(() => {
console.log("aaa")
clearTimeout(id)
})
})
function clickHandler() {
count.value = 200;
}
unwatch()
const count = ref(0);
let unwatch = watchEffect(() => {
console.log(count.value);
})
setTimeout(() => {
watchEffect(() => {
console.log(count.value)
})
})
function clickHandler() {
count.value++;
unwatch()
}
watch和computed 的区别
computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
`两个重要的小原则:`
1.所有`被Vue管理的函数,最好写成普通函数`,这样this的指向才是vm 或 组件实例对象
2.所有不被Vue所管理的函数(`定时器的回调函数、ajax的回调函数等、Promise的回调函数`),最好`写成箭头函数`,这样this的指向才是vm 或 组件实例对象。
工具函数和生命周期钩子函数
toRef和toRefs
`toRef`
const sum = toRef(porps, "count")
1.toRef 函数可以将一个响应式对象的属性转换为一个独立的 ref 对象。
2.返回的是一个指向源对象属性的 ref 引用,任何对该引用的修改都会同步到源对象属性上。
3.使用 toRef 时需要传入源对象和属性名作为参数。
`toRefs`
const sum = toRefs(porps).count
1.toRefs 函数可以将一个响应式对象转换为一个普通的对象,该对象的每个属性都是独立的 ref 对象。
2.返回的对象可以进行解构,每个属性都可以像普通的 ref 对象一样访问和修改,而且会保持响应式的关联。
3.toRefs 的使用场景主要是在将响应式对象作为属性传递给子组件时,确保子组件可以正确地访问和更新这些属性
`相同点`
1.toRef 和 toRefs 都用于将响应式对象的属性转换为 ref 对象。
2.转换后的属性仍然保持响应式,对属性的修改会反映到源对象上。
3.不管是使用 toRef 还是 toRefs 将响应式对象转成普通对象,在 script 中修改和访问其值都需要通过 .value 进行。
`不同点`
1.toRef 修改的是对象的某个属性,生成一个单独的 ref 对象。
2.toRefs 修改的是整个对象,生成多个独立的 ref 对象集合。
3.toRefs 适用于在组件传递属性或解构时使用,更加方便灵活,而 toRef 更适合提取单个属性进行操作。
生命周期函数
onBeforeMount(() => {
console.log("挂载前");
})
onMounted(() => {
console.log("挂载后");
})
onBeforeUpdate(() => {
console.log("更新前");
})
onUpdated(() => {
console.log("更新后");
})
onBeforeUnmount(() => {
console.log("卸载前");
})
onUnmounted(() => {
console.log("卸载后");
})
依赖注入
<template>
<div>
<ChildA/>
<button @click="count++">按钮</button>
</div>
</template>
<script setup>
import { provide, ref } from "vue"
import ChildA from "@/components/injectView/ChildA.vue"
const count = ref(1);
function setCommit(){
console.log("aaa");
}
provide("count", count)
provide("setCommit",setCommit)
</script>
<template>
<div>
<div>{{ count }}</div>
</div>
</template>
<script setup>
import { inject } from "vue"
const count = inject("count")
const setCommit=inject("setCommit");
setCommit()
</script>
组合式函数
核心逻辑完全一致,只是把它移到一个外部函数中去,并返回需要暴露的状态
import { ref, onMounted, onUnmounted } from "vue";
const x = ref(0);
const y = ref(0);
export default function mouseXY() {
addEvent();
return { x, y };
}
function addEvent() {
onMounted(() => {
document.addEventListener("mousemove", mouseHandler);
})
onUnmounted(() => {
document.addEventListener("mousemove", mouseHandler);
})
}
function mouseHandler(e) {
x.value = e.clientX;
y.value = e.clientY;
}
import mouseXY from "@/hooks/MouseXY.js";
const { x, y } = mouseXY();
完整的异步过程
<template>
<div>
<form @submit.prevent="submitHandler">
<input type="text" name="user" v-model="user">
<input type="password" name="password" v-model="password" autocomplete>
<button type="submit">提交</button>
</form>
<div v-if="result.error">{{ 通信失败 }}</div>
<div v-else-if="result.data">{{ result.data }}</div>
<div v-else>正在通信中...</div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { useLogin } from "@/hooks/Ajax.js"
const user = ref("");
const password = ref("");
let result = ref({})
function submitHandler() {
var fd = new FormData();
fd.set("user", user.value);
fd.set("password", password.value);
result.value = useLogin(fd)
}
</script>
import { ref } from "vue";
export function useLogin(body) {
const data = ref(null);
const error = ref(null);
fetch("http://localhost:4000/users/login", {
method: "POST",
body: body
}).then((result) => {
result.json().then((res) => {
data.value = res;
})
}).catch(e => {
error.value = e
})
return { data, error }
}
API基础
涵盖了以下方面的 API:
● `响应式 API:例如 ref() 和 reactive(),使我们可以直接创建响应式状态、计算属性和侦听器`
● `生命周期钩子:例如 onMounted() 和 onUnmounted(),使我们可以在组件各个生命周期阶段添加逻辑`
● `依赖注入:例如 provide() 和 inject(),使我们可以在使用响应式 API 时,利用 Vue 的依赖注入系统`
组合式优点:
1.更好的逻辑复用,组合式 API 解决了 mixins 的所有缺陷
2.更灵活的代码组织
3.更好的类型推荐
4.更小的生产包体积
组合式两种写法
setup函数和重要知识
1.在vue3组合式中不需要写data,在setup中返回的对象就是data数据
2.在setup()中不能使用this,因此不能使用this.$props this.$attrs
3.vue3组合式中有两种变量定义
`ref 当赋值发生改变时,会进行更新`
`reactive 主要用于定义引用类型`,和ref不同的地方在于,`改变引用地址将与原绑定内容分离,不会更新改变`
`setup()`
4.setup() 函数中有两个参数
1) 函数的第一个参数是组件的 props
2) 函数的第二个参数是一个 Setup 上下文对象
其中包括 ttrs、emits、slots、expose
5.defineProps
defineProps返回的props对象,是一个proxy对象,所有特性和reactive基本相同,只不过`由defineProps定义出的props对象的值是只读的`,还有在模板上可以单独属性直接使用
对于数据
写法1
`在script中使用 setup()函数`
<template>
<div>
<div>{{ count }}</div>
<ul>
<li v-for="(value, index) in list" :key="index">{{ value }}</li>
</ul>
<button @click="clickHandler">按钮</button>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
props: ["a"],
setup(props, minxi) {
console.log(props);
console.log(minxi);
const count = ref(1);
const list = ref({ a: 1, b: 2 })
return {
count,
list
}
},
methods: {
clickHandler() {
this.count++
`值是数组类型`
this.list = [4, 5, 6]
this.list.length = 0;
this.list.push(...[4, 5, 6])
this.list.push(10)
`值是对象类型`
this.list = { c: 3, d: 4 }
this.list.c = 30;
Object.keys(this.list).forEach(key => delete this.list[key]);
Object.assign(this.list, { c: 3, d: 4 })
}
}
}
</script>
写法2
`在script标签中加 setup`
<template>
<div>
<div>{{ count }}</div>
<ul>
<li v-for="(value, index) in arr" :key="index">{{ value }}</li>
</ul>
<button @click="clickHandler">按钮</button>
</div>
</template>
<script setup>
import { reactive, ref, defineProps } from "vue";
const count = ref(1);
const arr=ref([1,2,3]);
defineProps(['a']);
function clickHandler() {
count.value++,
list.push(10),
list.length = 0;
list.push(...[4, 5, 6])
arr.value.push(4, 5)
console.log(arr)
}
</script>
对于事件和函数
写法1
<template>
<div>
<SecondView :count="count" ref="sv" @change="(value)=>console.log(value)"></SecondView>
<button @click="count++">按钮</button>
</div>
</template>
<script>
import SecondView from "@/views/SecondView.vue"
export default {
name: 'App',
components: {
SecondView
},
data() {
return {
count: 1,
total: 1
}
},
mounted(){
console.log(this.$refs.sv.name);
this.$refs.sv.changeName();
}
}
</script>
<template>
<div>
{{ count }}--{{ sum }}
<!-- {{ count }}--{{ props1 }} -->
<!-- <button @click="clickHandler">按钮1</button> -->
</div>
</template>
<script>
import { ref, toRef, toRefs, onMounted } from "vue"
export default {
name: "SecondView",
props: ["count"],
setup(props, context) {
const sum = toRef(props, "count")
const props1 = toRefs(props)
const name = ref("谢天")
const changeName = () => {
name.value = "张三"
}
context.expose({
name,
changeName
})
return {
sum,
props1
}
}
}
</script>
写法2
`1.defineEmits 定义事件
2.defineProps 获取父组件传来的值
3.defineModel v-model 的使用
4.defineExpose 把值暴露给父级
`
<SecondView :count="count" @change="(value) => console.log(value)" ref="sv" v-model="total" />
<button @click="count++">按钮2</button>
{{ total }}
mounted() {
console.log(this.$refs.sv.name);
this.$refs.sv.change()
}
<template>
<div>
{{ count }}--{{ sum }}
{{ count }}--{{ props1 }}
<button @click="clickHandler">按钮1</button>
</div>
</template>
<script setup>
import { defineEmits,defineProps,toRef,toRefs,defineExpose,ref } from "vue"
const emits=defineEmits(["change"])
const props=defineProps(["count"])
const modelValue=defineModel({required:true})
const name=ref("xietian")
defineExpose({name})
const sum=toRef(props,"count")
function clickHandler(){
emits("change",1)
modelValue.value++
}
</script>
响应式核心
ref()和reactive()
`ref 当赋值发生改变时,会进行更新`
`reactive 主要用于定义引用类型`,和ref不同的地方在于,`改变引用地址将与原绑定内容分离,不会更新改变`
1.要求 ref用来定义非引用类型 reactive用来定义引用类型
2.ref也可以设置引用类型,这时候,value值就会变成使用reactive定义Proxy对象了
3.reactive不能设置非引用类型
4.reactive 不能设置为null类型,ref 可以设置为null类型
6.`在<script steup> 写法中`
所有使用ref定义的,修改值都需要使用这个变量的value值修改
count.value++,
所有使用reactive定义的,直接修改其值就行了
`使用`
const list = ref([1, 2, 3, 4])
const list = ref({ a: 1, b: 2 })
const obj = reactive({ a: 1, b: 2 })
const obj = reactive([1, 2, 3])
`值是数组类型`
this.list = [4, 5, 6]
this.list.length = 0;
this.list.push(...[4, 5, 6])
this.list.push(10)
`值是对象类型`
this.list.c = 30;
this.list = { c: 3, d: 4 }
Object.keys(this.list).forEach(key => delete this.list[key]);
Object.assign(this.list, { c: 3, d: 4 })
`深层`
list.value={a:1,b:2,c:{d:4}}
list.value.c=10
console.log(list);
obj.value={a:1,b:2,c:{d:4}}
obj.value.c.d=10
console.log(obj);
useAttrs()
<ChildB :count="count" a="10"/>
<p>{{ attrs.a }}</p>
const attrs = useAttrs()
console.log(attrs)
computed ()
`使用`
<input type="text" v-model="msg">
<div>{{ message }}</div>
const msg = ref("")
const message = computed(() => {
return "小波说:" + msg.value
})
<input type="text" v-model="a">
<div>{{ s }}</div>
<button @click="clickHandler">按钮</button>
const a = ref("");
const s = computed({
ser(value) {
a.value = value.replace("---", "")
},
get() {
return a.value + "???"
}
})
function clickHandler() {
console.log(s);
}
readonly()
const ab = readonly({ a: 1, b: 20 })
ab.a = 10
var obj = { a: 1, b: 2 }
const ab = readonly(new Map(Object.entries(obj)))
ab.set("a", 10)
watch()
`参数列表:`
参数1为需要监听的响应式对象(可以是单个对象,也可以是一个数组,也可以是一个getter函数),
参数2为监听对象发生变化时所执行的回调
参数3是一些配置项:immediate是否开启立即监听,deep是否开启深度监听,flush回调的触发时机,onTrack / onTrigger用于调试的两个函数
`使用`
const obj = reactive({ a: 1, b: 2 })
watch(obj, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
setTimeout(() => {
obj.a=10
}, 1000);
const obj = reactive({ a: 1, b: 2 })
watch(() => obj.b, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
setTimeout(() => {
obj.b=10
}, 3000);
const a = ref(1)
watch(a, (value) => {
console.log(value)
})
setTimeout(() => {
a.value=100
}, 3000);
const a = ref(0)
const b = ref("a")
watch([a, b], ([newValue_a, newValue_b], [oldValue_a, oldValue_b]) => {
console.log(newValue_a, newValue_b);
console.log(oldValue_a, oldValue_b)
})
setTimeout(() => {
a.value = 100;
b.value = "abc"
}, 3000);
watch(obj, (newValue, oldValue) => {
console.log(newValue)
})
setTimeout(() => {
obj.b.c = 100
}, 3000);
watch(() => obj.b, (newValue, oldValue) => {
console.log(newValue)
}, {
`deep: true`
})
setTimeout(() => {
obj.b.c = 100
}, 3000);
watchEffect()
第一个参数就是要运行的副作用函数。`这个副作用函数的参数也是一个函数,用来注册清理回调`。`清理回调会在该副作用下一次执行前被调用`,可以用来清理无效的副作用
const count = ref(0)
watchEffect(() => {
console.log(count)
})
setTimeout(() => {
count.value = 10;
}, 3000)
const count = ref(0);
watchEffect((fn) => {
console.log("bbb");
var id = setTimeout(() => {
count.value = 10;
console.log("ccc")
}, 3000);
fn(() => {
console.log("aaa")
clearTimeout(id)
})
})
function clickHandler() {
count.value = 200;
}
unwatch()
const count = ref(0);
let unwatch = watchEffect(() => {
console.log(count.value);
})
setTimeout(() => {
watchEffect(() => {
console.log(count.value)
})
})
function clickHandler() {
count.value++;
unwatch()
}
watch和computed 的区别
computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
`两个重要的小原则:`
1.所有`被Vue管理的函数,最好写成普通函数`,这样this的指向才是vm 或 组件实例对象
2.所有不被Vue所管理的函数(`定时器的回调函数、ajax的回调函数等、Promise的回调函数`),最好`写成箭头函数`,这样this的指向才是vm 或 组件实例对象。
工具函数和生命周期钩子函数
toRef和toRefs
`toRef`
const sum = toRef(porps, "count")
1.toRef 函数可以将一个响应式对象的属性转换为一个独立的 ref 对象。
2.返回的是一个指向源对象属性的 ref 引用,任何对该引用的修改都会同步到源对象属性上。
3.使用 toRef 时需要传入源对象和属性名作为参数。
`toRefs`
const sum = toRefs(porps).count
1.toRefs 函数可以将一个响应式对象转换为一个普通的对象,该对象的每个属性都是独立的 ref 对象。
2.返回的对象可以进行解构,每个属性都可以像普通的 ref 对象一样访问和修改,而且会保持响应式的关联。
3.toRefs 的使用场景主要是在将响应式对象作为属性传递给子组件时,确保子组件可以正确地访问和更新这些属性
`相同点`
1.toRef 和 toRefs 都用于将响应式对象的属性转换为 ref 对象。
2.转换后的属性仍然保持响应式,对属性的修改会反映到源对象上。
3.不管是使用 toRef 还是 toRefs 将响应式对象转成普通对象,在 script 中修改和访问其值都需要通过 .value 进行。
`不同点`
1.toRef 修改的是对象的某个属性,生成一个单独的 ref 对象。
2.toRefs 修改的是整个对象,生成多个独立的 ref 对象集合。
3.toRefs 适用于在组件传递属性或解构时使用,更加方便灵活,而 toRef 更适合提取单个属性进行操作。
生命周期函数
onBeforeMount(() => {
console.log("挂载前");
})
onMounted(() => {
console.log("挂载后");
})
onBeforeUpdate(() => {
console.log("更新前");
})
onUpdated(() => {
console.log("更新后");
})
onBeforeUnmount(() => {
console.log("卸载前");
})
onUnmounted(() => {
console.log("卸载后");
})
依赖注入
<template>
<div>
<ChildA/>
<button @click="count++">按钮</button>
</div>
</template>
<script setup>
import { provide, ref } from "vue"
import ChildA from "@/components/injectView/ChildA.vue"
const count = ref(1);
function setCommit(){
console.log("aaa");
}
provide("count", count)
provide("setCommit",setCommit)
</script>
<template>
<div>
<div>{{ count }}</div>
</div>
</template>
<script setup>
import { inject } from "vue"
const count = inject("count")
const setCommit=inject("setCommit");
setCommit()
</script>
组合式函数
核心逻辑完全一致,只是把它移到一个外部函数中去,并返回需要暴露的状态
import { ref, onMounted, onUnmounted } from "vue";
const x = ref(0);
const y = ref(0);
export default function mouseXY() {
addEvent();
return { x, y };
}
function addEvent() {
onMounted(() => {
document.addEventListener("mousemove", mouseHandler);
})
onUnmounted(() => {
document.addEventListener("mousemove", mouseHandler);
})
}
function mouseHandler(e) {
x.value = e.clientX;
y.value = e.clientY;
}
import mouseXY from "@/hooks/MouseXY.js";
const { x, y } = mouseXY();
完整的异步过程
<template>
<div>
<form @submit.prevent="submitHandler">
<input type="text" name="user" v-model="user">
<input type="password" name="password" v-model="password" autocomplete>
<button type="submit">提交</button>
</form>
<div v-if="result.error">{{ 通信失败 }}</div>
<div v-else-if="result.data">{{ result.data }}</div>
<div v-else>正在通信中...</div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { useLogin } from "@/hooks/Ajax.js"
const user = ref("");
const password = ref("");
let result = ref({})
function submitHandler() {
var fd = new FormData();
fd.set("user", user.value);
fd.set("password", password.value);
result.value = useLogin(fd)
}
</script>
import { ref } from "vue";
export function useLogin(body) {
const data = ref(null);
const error = ref(null);
fetch("http://localhost:4000/users/login", {
method: "POST",
body: body
}).then((result) => {
result.json().then((res) => {
data.value = res;
})
}).catch(e => {
error.value = e
})
return { data, error }
}