provide 与 inject
父组件与后代组件的通讯方式
父组件:提供数据
<script setup lang="ts">
import { ref, provide } from 'vue'
const color = ref<string>()
//提供数据
provide('color', color)
</script>
后代组件:接收(注入数据)
<script setup lang="ts">
import { inject } from 'vue'
const color = inject('color')
</script>
兄弟组件传值 Bus 手动简单实现
type BusType = {
emit: (name: string) => void
on: (name: string, callback: Function) => void
}
type ParamsKey = string | number | symbol
type List = {
[key: ParamsKey]: Array<Function>
}
class Bus implements BusType {
list: List
constructor() {
this.list = {}
}
// 订阅事件
on(name: string, callback: Function) {
// fn = []
let fn: Array<Function> = this.list[name] || []
/* fn = [ (val: boolean) => {flag.value = val}] */
fn.push(callback)
// list = { getFlagMsg:[ (val: boolean) => {flag.value = val}] }
this.list[name] = fn
}
// 发布事件
emit(name: string, ...args: any[]) {
// eventName=[(val: boolean) => {flag.value = val}]
let eventName: Array<Function> = this.list[name]
eventName.forEach(fn => {
fn.apply(this, args)
})
}
}
export default new Bus()
mitt库 实现兄弟组件传参
创建Mitt 文件 导出一个 mitt()
import mitt from 'mitt'
export default mitt()
发布:
import Mitt from '@/Mitt/Mitt'
import { ref } from 'vue'
const flag = ref<boolean>(false)
const send = () => {
flag.value = !flag.value
Mitt.emit('getFlagMsg', flag)
Mitt.emit('getFlagMsg2', flag)
}
订阅:
mport Mitt from '@/Mitt/Mitt'
import { ref } from 'vue'
const flag = ref<boolean>()
const getFlagMsg = (val: any) => {
flag.value = val
}
// 订阅一个事件
Mitt.on('getFlagMsg', getFlagMsg)
// 订阅所有事件
/* Mitt.on('*', (type, val) => {
console.log(type)
console.log(val)
}) */
// 取消订阅
// 取消指定
// Mitt.off('getFlagMsg', getFlagMsg)
// 取消所有
Mitt.all.clear()
TSX 的基本使用
文件导出为一个组件
// tsx 语法
// 模板语法为 单括号 模板不会解析 ref变量 需要 .value 使用值
// 支持 v-model v-show v-bind( {}代替 ) 不支持 v-if 可使用三元表达式替换 不支持 v-for 可使用 map方法代替
// 事件 onEvent = { () => 函数名() } 或 onEvent = { 函数名 }
// props emit 的使用
// 插槽 slot
// 定义一个组件 A 渲染函数方式创建
const A = (_: any, { slots }: SetupContext) => {
console.log(slots);
return <div>
<h1>{slots.default ? slots.default() : '默认显示内容'}</h1>
<h1>{slots.bar?.()}</h1>
</div>
}
// 封装一个组件
import { defineComponent, ref, type SetupContext } from "vue";
type Props = {
title?: string
}
const appTsx = defineComponent(
{
// props: ['title'],
props: {
title: String
},
emits: ['getMsg'],
setup(props: Props, { emit }) {
const name = ref<string>('张三')
const flag = ref<boolean>(false)
const num = ref<number>(1)
const data = [{ name: '1' }, { name: '2' }, { name: '3' }]
// 显示隐藏
const showHide = () => {
flag.value = !flag.value
}
// 自定义事件
const send = () => {
console.log("子组件发送数据了");
emit('getMsg', '我是TSX中的数据')
}
// 定义两个插槽
const slotData = {
default: () => (<div>默认插槽</div>),
bar: () => (<div>bar插槽</div>)
}
// 返回一个渲染函数
return () => (
<>
<A v-slots={slotData}></A>
<hr />
{/* 绑定事件 */} <button onClick={showHide}>显示/隐藏</button>
{/* v-show */} <div v-show={flag.value}>{name.value}</div>
{/* v-model */} <input type="text" v-model={name.value} />
{/* v-bind */} <div data-index={num.value}>v-bind</div>
<hr />
<h5 style={"color:red"}>v-if:</h5>
{/* v-if */} <div>{flag.value ? <div>A</div> : <div>B</div>}</div>
<hr />
<h5 style={"color:red"}>v-for:</h5>
{/* v-for => map */} {data.map(val => <div> {val.name}</div>)}
<hr />
{/* 接收props */} <div>{props?.title}</div>
{/* emit 发布事件 */} <button onClick={() => send()}>传递数据</button>
</>
)
}
}
)
export default appTsx
v-model 的高级用法
语法糖实现 子组件影响父组件数据
父组件:
<ChildVue
// .KIng 自定义修饰符
v-model:iptVal.KIng="iptVal"
//默认为 v-model:modelValue
v-model="flag"
>
</ChildVue>
<script setup lang="ts">
import { ref } from 'vue'
import ChildVue from './component/Child.vue'
const flag = ref<boolean>(true)
const iptVal = ref<string>('张三')
</script>
子组件:
<template>
<section>
// :value 使用 props中的属性
父组件值:<input type="text" :value="iptVal" @input="getIptVal" />
</section>
</template>
<script setup lang="ts">
const props = defineProps<{
modelValue: boolean
iptVal: string
// iptVal(已使用的属性名保持一致)+ Modifiers 自定义修饰符
iptValModifiers?: {
// 修饰符名称
KIng: boolean
}
}>()
//配合 defineEmits(['update:属性名'])
const emit = defineEmits(['update:modelValue', 'update:iptVal'])
const close = () => {
emit('update:modelValue', false)
}
const getIptVal = (e: Event) => {
const target = e.target as HTMLInputElement
// 自定义修饰符后 可以自定义操作值 再进行返回
const val = props.iptValModifiers?.KIng ? target.value + 'KIng' : target.value
emit('update:iptVal', val)
}
</script>
自定义指令
钩子函数
// 配置的生命周期 都可以接收4个参数
// 前两个 el:绑定指令的DOM元素
/* 第二个 binding对象 属性:
instance:使用指令的组件实例。
value:传递给指令的值。例如,在 v-my-directive="1 + 1" 中,该值为 2。
oldValue:先前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否有更改都可用。
arg:传递给指令的参数(如果有的话)。例如在 v-my-directive:foo 中,arg 为 "foo"。
modifiers:包含修饰符(如果有的话) 的对象。例如在 v-my-directive.foo.bar 中,修饰符对象为 {foo: true,bar: true}。
dir:一个对象,在注册指令时作为参数传递。 */
const vBgc: Directive = {
// created 元素初始化的时候
created() {
console.log('created => 元素初始化前')
},
// beforeMount 指令绑定到元素后调用 只调用一次
beforeMount() {
console.log(' beforeMount => 指令绑定到元素后调用 只调用一次')
},
// mounted 元素插入父级dom调用
mounted(el: HTMLElement, binding: DirectiveBinding<binding>) {
console.log('mounted => 元素插入父级dom调用')
el.style.background = binding.value.background
},
// beforeUpdate 元素被更新之前调用 binding.value 发生变化时执行
beforeUpdate() {
console.log('beforeUpdate => 元素被更新之前调用')
},
// updated 元素更新后调用 binding.value 发生变化时执行
updated() {
console.log('updated => 元素更新后调用')
},
// beforeUnmount 在元素被移除前调用
beforeUnmount() {
console.log('beforeUnmount => 在元素被移除前调用')
},
// unmounted 指令被移除后调用 只调用一次
unmounted() {
console.log('unmounted => 指令被移除后调用 只调用一次 ')
}
}
局部自定义指令(简写):mounted 与 updated 钩子函数中的操作一致时可简写为:
// 只关注 mounted 与 updated 生命周期时可以触发简写
const vBgc: Directive = (
el: HTMLElement,
binding: DirectiveBinding<binding>
) => {
el.style.background = binding.value.background
}
全局自定义指令:
1.定义自定义指令配置对象
import type { DirectiveBinding, ObjectDirective } from 'vue'
const iptFocus: ObjectDirective = {
mounted(el: HTMLInputElement, binding: DirectiveBinding) {
el.focus()
}
}
export default iptFocus
2.全局注册
// 导入自定义指令对象文件
import iptFocus from "./Directive";
// 全局注册自定义指令
app.directive('focus', iptFocus)
3.使用
<!-- 使用全局注册的 表单聚焦指令 -->
<input type="text" v-focus />