【第三章】

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 />
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值