精读VUE3文档
vue一些计算属性及watch监听的一些内容
计算属性
getter 和 setter
const firstName = ref('Kate')
const lastName = ref('Jen')
const fullName = computed({
// getter
get(){
return firstName.value + ' ' + lastName.value;
},
// setter
set(newValue){
// Es6结构赋值
[firstName.value,lastName.value] = newValue.split(' ');
}
})
fullName.value = "John Lee" // 此处会触发Setter函数.firstName和lastName也会相应更新
computed具有缓存的作用
计算属性会追踪依赖,如果依赖没有变动,将自动返回缓存中的数据,而调用方法每次重新渲染的的时候都会重新执行,会消耗更多的性能
watch 监听
1.watch监听源的几种形式
const num = ref(2)
const obj = ref({key:1})
watch(num,()=>{}) // 监听单个的 ref响应式数据
watch(()=>obj.key,(newVal)=>{}) // 监听一个getter函数
watch(()=>obj.value.key + num.value,(sum)=>{}) // 监听一个getter函数
watch([num,obj],(newVal1,nweVal2)=>{}) // 监听一个数组2.watch深度监听和立即执行
const num = ref(2)
const obj = ref({key:1,deepKey:{num:3}})
const updateNum = ()=>{
return num.value+obj.value.deepKey.num
}
watch(obj,()=>{
// 达到深度监听
},{deep:true})
watch(obj,()=>{
// 立即执行
},{immediate:true}) 3.watchEffect 会在监听的依赖数据发生变化时直接调用,而不需要指定明确的监听源
const id = ref(1)
const data = ref()
watchEffect(async ()=>{
const res = await fetch(`http://api.details/${id}`)
data.value = res
})4.watch 回调函数的触发机制, watchEffect 后置刷新 和 watchPostEffect
// 当响应数据发生变化时,dom和watch同时监听到。此时,watch的回调将会vue组件更新之前被调用。获取组件dom数据是组件更新之前的
watch(somRefProperty,()=>{
let dom = document.querySelector('...') // 数据更新之前的dom
})
// 后置刷新的方式。配置flush为post
watch(somRefProperty,()=>{
let dom = document.querySelector('...') // 数据更新之后的dom
},{flush:'post'})
watchEffect(()=>{
let dom = document.querySelector('...') // 数据更新之后的dom
},{flush:'post'})
// 后置刷新的watchEffect 可以简写为 watchPostEffect
watchPostEffect(()=>{
let dom = document.querySelector('...') // 数据更新之后的dom
})组件
1.component元素 动态组件
import componentA from "./xx.vue"
import componentB from "./xx.vue"
const currentComponent = computed(()=>route.query.isA?componentA:componentB)
<component :is="currentComponent"></component>
<component is="div"></component>
<component is="a" href="/a/b"></component>2. 组件元素 位置限制的问题处理
import customTr from './tr/vue'
<table>
<custom-tr></custom-tr> 此处使用自定义组件,会被忽略掉
</table>
// ---------------- 正确使用 ---------------
<table>
<tr is="vue:custom-tr"></tr> 此处使用自定义组件,会被忽略掉
</table> 3. 组件的引用和获取(ref)
<script setup>
import child from './child'
const childRef= ref(null)
onMounted(()=>{
// 在挂载之后获取子组件中的数据
const data = childRef.data
})
</script>
<template>
<child ref="childRef"></child>
</template><script setup>
const data = ref('我是子组件的数据')
const fn = ()=>{
alert()
}
// 注意:在使用了 script setup 组合是api形式的组件中,子组件的数据是私有的不允许父组件访问。
// 必须使用 defineExpose 将数据显式的暴露出去才能被父组件访问的到
defineExpose({
data,
fn
})
</script>
<template>
<span>我是子组件,数据:{{data}}</span>
</template>4. 组件透传-attribute
父组件在引用组件上属性(class,style,@click等)会被透传给子组件(子组件根节点可以使用$attrs接受到)
// 父组件
import child from './child'
<child class="test" @click="fn"></child>
//子组件会被渲染成这样(这个div是子组件的根节点)
<button class="test" @click="fn"></button>
// 子组件中使用$attrs
<button>{{$attrs.class}}</button>
//取消属性透传
defineOptions({
inheritAttrs: false
})
//如果不是根节点怎么使用透传的属性?使用v-bind 配和 inheritAttrs: false 即可实现
<div class="child-components-wrap">
<button class="btn" v-bind="$attrs">click me</button>
</div>
defineOptions({
inheritAttrs: false
})
// 子组件有多个根节点-需要显示的绑定透传的attrs
<header></header>
<main v-bind="$attrs"></main>
<footer></footer> 5. 组件js如何透传-attribute
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>组合式函数
- 组合式函数是vue3.0中新增的api,可以用来代替vue2.x中的mixin
const useMouse = () => {
const state = ref({
x: 0,
y: 0
})
const update = (e: MouseEvent) => {
state.value.x = e.pageX
state.value.y = e.pageY
}
const onMouseMove = (e: MouseEvent) => {
update(e)
}
return {
state,
update,
onMouseMove
}
}
// 使用useMouse
const { state, update, onMouseMove } = useMouse()
// 异步实现
// fetch.js
import { ref, watchEffect, toValue } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const fetchData = (dt) => {
// toValue() 是一个在 3.3 版本中新增的 API。它的设计目的是将 ref 或 getter 规范化为值
fetch(toValue(url))
.then((res) => res.json())
.then((json) => (data.value = json))
.catch((err) => (error.value = err))
}
watchEffect(() => {
// reset state before fetching..
fetchData(url)
})
return { data, error }
}自定义指令
自定义指令是vue2.x中使用的api,在vue3.0中进行了升级,使用更加简单
1.注册自定义指令
// 全局注册
const app = createApp({})
app.directive('focus',{
//
})2.指令的钩子
const myDirective = {
// 在绑定元素的 attribute 前
// 或事件监听器应用前调用
/**
* @el 指令所绑定的元素 这里可以直接操作DOM
* @binding {value,oldValue,arg, modifiers,instance:使用该指令的组件实例,dir}
* @vnode 代表绑定元素的底层 VNode
* @prevVnode 代表之前的渲染中指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。
*/
created(el, binding, vnode, prevVnode) {
// 下面会介绍各个参数的细节
},
// 在元素被插入到 DOM 前调用
beforeMount(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件更新前调用
beforeUpdate(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都更新后调用
updated(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载前调用
beforeUnmount(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载后调用
unmounted(el, binding, vnode, prevVnode) {}
}
// 示例
<button v-click:double.stop="fn">按钮</button>
// binding 对象
{
arg: 'double',
modifiers: { stop: true },
value: fn,
oldValue: undefined,///* 上一次更新时 `fn` 的值 */
instance: Vue 实例,
}
// 简化形式
<input v-color="color">按钮</input>
app.directive('color',(el,binding)=>{
// 这会在 `mounted` 和 `updated` 时都调用
el.style.color = binding.value
})