javaScript Vue3 新特性

一.Composition API

        选项式 API 与 Composition API 属于两种心智模型,选项式就是我们所说的配置式,它通过前期的内容约定,结构规范保证程序健壮性及可读性。组合式显然比选项式灵活,除此以外,组合式实现了 UI 复用与状态逻辑复用的分离。

1.1常见的Composition API

  1. setUp: 组合式API的入口

  2. ref 和 reactive 有什么区别?   
    ①基本类型 vs 对象类型

           ref:可以处理任何类型的值(基本类型和对象类型)

           reactive:只能处理对象类型(Object, Array, Map, Set等)

     ②访问方式

          ref:需要通过 .value 访问和修改值

           reactive:直接访问和修改属性

           ③ 模板中使用

                ref:在模板中自动解包,不需要 .value

        <div>{{ count }}</div> <!-- 不需要 count.value --

                reactive:直接访问属性

                        <div>{{ state.count }}</div>

            ④  解构/扩展

                ref:保持响应性,可以单独传递

                reactive:解构或扩展会失去响应性,需要使用 toRefs 保持响应性

             ⑤ 实现原理

                   ref:使用对象包装,通过 getter/setter 实现响应式

                    reactive:使用 Proxy 实现深层响应式

        3. watchEffect 与 watch 的区别

                懒执行副作用;

                更加明确是应该由哪个状态触发侦听器重新执行;

                可以访问所侦听状态的前一个值和当前值。

        4. 生命周期

        
        5. 异步组件

        在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。换言之,我们的组件可能不再是同步导入或者组件需要等待 Promise resolve 完成后才被渲染。这样的组件我们称为异步组件。

<script setup>
import { defineAsyncComponent } from 'vue'

const AdminPage = defineAsyncComponent(() =>
  import('./components/AdminPageComponent.vue')
)
</script>

<template>
  <AdminPage />
</template>

注意: 通常是和<Suspense>标签配合使用

<template>
  <Suspense>
    <!-- 默认插槽:显示异步组件 -->
    <template #default>
      <AsyncComponent />
    </template>
 
    <!-- 备用插槽:显示加载中的内容 -->
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>
 
<script setup lang="ts">
import { defineAsyncComponent } from 'vue';
 
// 定义一个异步组件
const AsyncComponent = defineAsyncComponent(() =>
  import('./AsyncComponent.vue')
);
</script>
6. 自定义指令

权限控制指令

app.directive('permission', (el, binding) => {
    const { value } = binding
    //const userRoles = getCurrentUserRoles() // 获取当前用户角色的方法
    const userRoles = ['admin']  //模拟数据
    if (value && value instanceof Array && value.length > 0) {
        const hasPermission = userRoles.some(role => value.includes(role))
        if (!hasPermission) {
            el.parentNode && el.parentNode.removeChild(el)
        }
    } else {
        throw new Error(`需要指定权限,例如 v-permission="['admin','editor']"`)
    }
}
)

<template>
  <div class="container">
    <button v-permission="['admin']">管理员按钮</button>
    <button v-permission="['editor']">编辑者按钮</button>
  </div>
</template>

指令的钩子会传递以下几种参数:

  • el:指令绑定到的元素。这可以用于直接操作 DOM。

  • binding:一个对象,包含以下属性。

    • value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2

    • oldValue:之前的值,仅在 beforeUpdateupdated 中可用。无论值是否更改,它都可用。

    • arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"

    • modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }

    • instance:使用该指令的组件实例。

    • dir:指令的定义对象。

  • vnode:代表绑定元素的底层 VNode。

  • prevNode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdateupdated 钩子中可用。

7. Teleport

        该特性允许你将组件内的某个子组件挂载到任意 HTML 节点上,<Teleport> 只改变了渲染的 DOM 结构,它不会影响组件间的逻辑关系。也就是说,如果 <Teleport> 包含了一个组件,那么该组件始终和这个使用了 <teleport> 的组件保持逻辑上的父子关系。传入的 props 和触发的事件也会照常工作。

<Teleport> 接收一个 to prop 来指定传送的目标。to 的值可以是一个 CSS 选择器字符串(如:to=".container"to="#container),也可以是一个 DOM 元素对象(如:to="body")。

   <Teleport to="body">
      <!-- 使用这个 modal 组件,传入 prop -->
      <modal :show="isShow" @close="isShow = false">
        <template #header>
          <h3>custom header</h3>
        </template>
      </modal>
    </Teleport>

8. 自定义Hooks

        我们通过自定义 Hook,可以将组件的状态与 UI 实现分离,虽然这个 api 和早期的 mixin 非常像,但是他的设计思想实在先进太多。

  1. import { Ref, readonly, ref } from 'vue'
    
    // 判断是否为数字
    const isNumber = (value: unknown): value is number => typeof value === 'number'
    
    export interface UseCounterOptions {
      /**
       *  Min count
       */
      min?: number
    
      /**
       *  Max count
       */
      max?: number
    }
    
    export interface UseCounterActions {
      /**
       * Increment, default delta is 1
       * @param delta number
       * @returns void
       */
      inc: (delta?: number) => void
    
      /**
       * Decrement, default delta is 1
       * @param delta number
       * @returns void
       */
      dec: (delta?: number) => void
    
      /**
       * Set current value
       * @param value number | ((c: number) => number)
       * @returns void
       */
      set: (value: number | ((c: number) => number)) => void
    
      /**
       * Reset current value to initial value
       * @returns void
       */
      reset: () => void
    }
    
    export type ValueParam = number | ((c: number) => number)
    
    function getTargetValue(val: number, options: UseCounterOptions = {}) {
      const { min, max } = options
      let target = val
      if (isNumber(max)) {
        target = Math.min(max, target)
      }
      if (isNumber(min)) {
        target = Math.max(min, target)
      }
      return target
    }
    
    function useCounter(
      initialValue = 0,
      options: UseCounterOptions = {},
    ): [Ref<number>, UseCounterActions] {
      const { min, max } = options
    
      const current = ref(
        getTargetValue(initialValue, {
          min,
          max,
        }),
      )
    
      const setValue = (value: ValueParam) => {
        const target = isNumber(value) ? value : value(current.value)
        current.value = getTargetValue(target, {
          max,
          min,
        })
        return current.value
      }
    
      const inc = (delta = 1) => {
        setValue(c => c + delta)
      }
    
      const dec = (delta = 1) => {
        setValue(c => c - delta)
      }
    
      const set = (value: ValueParam) => {
        setValue(value)
      }
    
      const reset = () => {
        setValue(initialValue)
      }
    
      return [
        readonly(current),
        {
          inc,
          dec,
          set,
          reset,
        },
      ]
    }
    
    export default useCounter

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值