国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Vue3自定義指令實踐:使用h函數渲染自定義組件到指令中

開發 前端
為了可以應對更多場景,我們期望可以配置加載中的提示信息,不配置使用默認值,如果是 false ,那么僅展示 loading 圖。

?? 關鍵接口介紹

最近想體驗下自定義指令功能,看了看文檔和 vue2 差異不大,語法如下:

const myDirective = {
// 在綁定元素的 attribute 前 
// 或事件監聽器應用前調用
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) {}
}

起初,最大的痛點是需要手動創建 dom ,然后插入 el 中。

const loadingDom = document.createElement('div', {calss: 'loading'})
el.append(loadingDom)

這樣好難受啊,我不想寫原生 dom ,能不能寫個組件渲染到指令里呢?

我想起了我之前看到的幾個 vue 接口,

  • h函數,也就是 vue 提供的創建 vNode 的函數
  • render函數:將 vNode 渲染到 真實 dom 里的函數

h函數用法如下:

// 完整參數簽名
function h(
    type: string | Component,
    props?: object | null,
    children?: Children | Slot | Slots
): VNode

例如:

import { h } from 'vue'

const vnode = h('div', { class: 'container' }, [
  h('h1', 'Hello, Vue 3'),
  h('p', 'This is a paragraph')
])

我們使用h函數創建了一個 VNode,它表示一個包含 div、h1、p 的 DOM 結構。其中,div 的 class 屬性為 container

?? 自定義 loading 組件

然而,當我使用 props 為組件傳遞值時,發現是徒勞的。

import Loading from './components/Loading.vue';

cconst option = {
    msg: '一大波僵尸來襲',
    loading: true
}

const vnode = h(
    Loading,
    { id: 'loading', ...option}
)

僅僅如下圖一樣,我以為是給組件的 props,實際上是 dom 的 props。

圖片圖片

此時我們的組件只能通過 $attrs 來獲取這些 props 了,如下:

<template>

  <div class="loading">
    <div></div>
    <span v-if="$attrs.msg !== false">{{ $attrs.msg }}</span>
  </div>
  
</template>

接著我們給組件實現 loading 動畫,當然你也可以直接使用組件庫的 loading 組件。

我的實現如下:

<style>
  @keyframes identifier {
    100% {
      -webkit-transform: rotate(360deg);
      transform: rotate(360deg);
    }
  }
  .loading {
    height: 100px;
    width: 100%;
  }
  .loading div {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    border: 2px solid green;
    margin: 25px auto;
    border-top: none;
    border-left: none;
    animation: identifier 1s infinite linear;
  }
</style>

?? 自定義指令

接下來我們封裝自定義指令。

我們的思路是:

  • mounted 階段,如果是 true,那么渲染組件,否則什么都不做。
  • update 階段,如果 true 則重新渲染組件,如果 false 則渲染 vnode

為了可以應對更多場景,我們期望可以配置加載中的提示信息,不配置使用默認值,如果是 false ,那么僅展示 loading 圖。所以參數類型如下:

interface Props  {loading: boolean, msg?: string | false}

v-loading: boolean | Props

由于可能是布爾值,也可能是對象,我們需要初始化配置參數

function formatOption (value: boolean | Props) {
  const loading = typeof value === 'boolean'
      ? value 
      : value.loading
  const option = typeof value !== 'boolean'
    ? Object.assign(defaultOption, value)
    : {
      loading,
      ...defaultOption
    }
  return { loading, option }
}

接著再 mounted 階段獲取格式化后的 loading 和 option,如果為 true 則直接渲染組件。

const vLoading: Directive<HTMLElement, boolean | Props> = {
  mounted(el, binding) {

    const { loading, option } = formatOption(binding.value)

    loading && renderLoading(el, option)

  }
}

function renderLoading (el: HTMLElement, option: Props) {
  const vnode = h(
    Loading,
    { id: 'loading', ...option}
  )
  el.removeChild(el.children[0])
  render(vnode, el)
}

如果進入 update 階段,則根據情況選擇渲染 laoding 組件還是 vnode。

const vLoading: Directive<HTMLElement, boolean | Props> = {
  mounted(el, binding) {

    const { loading, option } = formatOption(binding.value)

    loading && renderLoading(el, option)

  },
  updated(el: HTMLElement, binding, vnode) {

    const { loading, option } = formatOption(binding.value)

    if (loading) {
      renderLoading(el, option)
    } else {
      renderVNode(el, vnode)
    }

  },
}

function renderLoading (el: HTMLElement, option: Props) {
  const vnode = h(
    Loading,
    { id: 'loading', ...option}
  )
  el.removeChild(el.children[0])
  render(vnode, el)
}

function renderVNode (el: HTMLElement, vnode: VNode) {
  el.querySelector('#loading')?.remove()
  render(vnode, el)
}

我們驗證下功能:

  • 默認功能
const loading = ref(true)

setTimeout(() => loading.value = false, 2000)

</script>

<template>
  <div style="width: 300px" v-loading=laoding>
    <h1>加載成功</h1>
  </div>
</template>

圖片圖片

  • 自定義文本
<template>
  <div style="width: 300px" v-loading="{ loading, msg: '一大波僵尸來襲' }">
    <h1>加載成功</h1>
  </div>
</template>

圖片圖片

  • 不展示文本
<template>
  <div style="width: 300px" v-loading="{ loading, msg: false }">
    <h1>加載成功</h1>
  </div>
</template>

圖片圖片

?? 最后

今天的分享就到這了,如果有問題,可以評論區告訴我,我會及時更正。

以下是完整的代碼。

<template>

  <div class="loading">
    <div></div>
    <span v-if="$attrs.msg !== false">{{ $attrs.msg }}</span>
  </div>
  
</template>
  
<script lang="ts">
export default {  
}
</script>
  
<style>
  @keyframes identifier {
    100% {
      -webkit-transform: rotate(360deg);
      transform: rotate(360deg);
    }
  }
  .loading {
    height: 100px;
    width: 100%;
  }
  .loading div {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    border: 2px solid green;
    margin: 25px auto;
    border-top: none;
    border-left: none;
    animation: identifier 1s infinite linear;
  }
</style>
<script setup lang="ts">
import { Directive, VNode, h, ref, render  } from 'vue';
import Loading from './components/Loading.vue';

const defaultOption: {msg?: string | false} = {
  msg: '努力加載中'
}

interface Props  {loading: boolean, msg?: string | false}

function formatOption (value: boolean | Props) {
  const loading = typeof value === 'boolean'
      ? value 
      : value.loading
  const option = typeof value !== 'boolean'
    ? Object.assign(defaultOption, value)
    : {
      loading,
      ...defaultOption
    }
  return { loading, option }
}

function renderLoading (el: HTMLElement, option: Props) {
  const vnode = h(
    Loading,
    { id: 'loading', ...option}
  )
  el.removeChild(el.children[0])
  render(vnode, el)
}

function renderVNode (el: HTMLElement, vnode: VNode) {
  el.querySelector('#loading')?.remove()
  render(vnode, el)
}

const vLoading: Directive<HTMLElement, boolean | Props> = {
  mounted(el, binding) {

    const { loading, option } = formatOption(binding.value)

    loading && renderLoading(el, option)

  },
  updated(el: HTMLElement, binding, vnode) {

    const { loading, option } = formatOption(binding.value)

    if (loading) {
      renderLoading(el, option)
    } else {
      renderVNode(el, vnode)
    }

  },
}

const loading = ref(true)

setTimeout(() => loading.value = false, 2000)

</script>

<template>
  <div style="width: 300px" v-loading="{ loading, msg: '一大波僵尸來襲' }">
    <h1>加載成功</h1>
  </div>
</template>

責任編輯:武曉燕 來源: 萌萌噠草頭將軍
相關推薦

2021-11-30 08:19:43

Vue3 插件Vue應用

2022-07-26 01:06:18

Vue3自定義指令

2021-07-05 15:35:47

Vue前端代碼

2022-02-22 13:14:30

Vue自定義指令注冊

2023-07-21 19:16:59

OpenAIChatGPT

2020-12-28 10:10:04

Vue自定義指令前端

2024-09-26 14:16:07

2022-08-01 11:41:00

Vue插件

2010-10-25 16:05:07

oracle自定義函數

2022-04-24 15:17:56

鴻蒙操作系統

2010-09-14 16:47:23

SQL自定義函數

2017-05-18 12:36:16

android萬能適配器列表視圖

2017-05-19 10:03:31

AndroidBaseAdapter實踐

2023-12-21 09:00:21

函數React 組件useEffect

2010-05-11 13:16:21

Unix awk

2009-06-24 15:13:36

自定義JSF組件

2023-02-20 15:20:43

啟動頁組件鴻蒙

2015-02-12 15:33:43

微信SDK

2021-12-24 15:46:23

鴻蒙HarmonyOS應用

2024-06-03 10:00:51

Vue 3語法插槽
點贊
收藏

51CTO技術棧公眾號

欧美曰成人黄网| 北条麻妃在线一区二区| 久久精品视频91| 紧缚捆绑精品一区二区| 成人有码在线视频| 久久91精品| 91精品国产乱码久久久久久久久| 日本精品在线一区| 亚洲成人在线网| 羞羞视频在线观看不卡| 欧美二区乱c少妇| 91在线网址| 在线亚洲一区二区| 伊人网站在线| 色中色一区二区| 一级毛片在线| 色香蕉久久蜜桃| 99免在线观看免费视频高清| 欧洲人成人精品| h视频在线观看免费| 欧美自拍偷拍午夜视频| 999国产在线视频| 欧美美女网站色| gogo在线高清视频| 亚洲激情视频在线| 国产v综合v| 欧美日韩国产成人在线| 日韩成人18| 日av在线播放中文不卡| 最新国产一区| 亚洲一区精品电影| 国产日韩免费| 日韩亚洲欧美一区二区| 91麻豆成人久久精品二区三区| 又色又爽又高潮免费视频国产| 国产欧美精品一区二区色综合 | 91久久青草| 久久久在线视频| 波多野结衣在线播放一区| 国产精品影院在线观看| 亚洲成人免费| 日本高清不卡三区| 国产精品综合一区二区| 日韩亚洲在线视频| 亚洲国产三级在线| v天堂福利视频在线观看| 亚洲第一中文字幕在线观看| 三上悠亚亚洲一区| 97视频在线观看成人| 亚洲精品2区| 日本一区高清在线视频| 成人精品免费网站| 在线看片黄色| 日韩美女一区二区三区四区| 欧美天堂一区二区| 国产精品色婷婷视频| 亚洲欧美成人| 欧美二区在线视频| 欧美日韩精品在线| sese综合| 国产精选久久久久久| 日韩成人一级大片| 亚洲成人天堂网| 制服丝袜av成人在线看| 久久国产精品美女| 国产厕所精品在线观看| 成人高清av在线| 青青草视频在线免费观看| 亚洲欧美精品在线| 欧美精品系列| 欧美性猛交内射兽交老熟妇| 一二三区精品视频| 芒果视频成人app| 91亚洲一区精品| 国产suv精品一区二区883| 国产日本韩国在线播放| 欧美va在线播放| 精品一级毛片| 91视频最新入口| 欧美日韩在线电影| 亚洲小说图片| 欧美一区二区激情| 欧美在线看片a免费观看| av日韩在线免费观看| 国产精品日韩欧美一区二区三区 | 国产精品jizz视频| 国产亚洲综合在线| 污污影院在线观看| 国产精品99久久久久久人 | 日本成人三级电影网站| 亚洲欧美一区二区三区极速播放 | 亚洲精品电影网在线观看| 精品一区二区三| 成年人看的毛片| 欧美日韩高清在线| 你懂的视频欧美| 亚洲精品少妇一区二区| 欧美三级视频在线| 国产成人精品三级高清久久91| 视色,视色影院,视色影库,视色网 日韩精品福利片午夜免费观看 | 蜜桃成人在线视频| 欧美极品在线视频| 国产一区 二区 三区一级| 国产尤物视频在线| 2021久久精品国产99国产精品| 国产精品亚洲专一区二区三区 | 欧美亚洲综合视频| 欧洲精品久久| 91久久精品国产91性色tv| 色天下一区二区三区| 真实国产乱子伦对白视频| 日韩午夜小视频| 亚洲人人精品| 深夜福利免费在线观看| 热久久免费视频精品| 久久久久久夜精品精品免费| 日本孕妇大胆孕交无码| 久久99国产精品99久久| 一本大道久久a久久精品综合| 国产亚洲一区| 一个人看的免费视频色| 国产成人一区二区| 一区二区欧美国产| 国产一区二区欧美| 男女午夜视频在线观看| 国产成人精品电影久久久| 国产精品丝袜一区| 好吊妞视频这里有精品| 台湾十八成人网| 热久久免费国产视频| 亚洲欧美福利一区二区| 日韩大胆成人| jlzzjlzz欧美大全| 国产精品日日摸夜夜添夜夜av| 一区二区三区不卡在线观看| 一道本一区二区三区| 动漫h在线观看| 亚洲最大av在线| 欧美最猛黑人xxxxx猛交| 在线看片欧美| 国产啊啊啊视频在线观看| 午夜精品福利一区二区| 亚洲国产又黄又爽女人高潮的| 久久99精品久久久久久国产越南 | 欧美这里只有精品| 日韩中文字幕亚洲| 久久精品视频在线免费观看| 中文无码日韩欧| 国产主播在线资源| 91久久精品国产91久久| 欧美日本在线看| 老色鬼精品视频在线观看播放| 英国三级经典在线观看| 亚洲熟妇无码一区二区三区| 九九热精品视频在线播放| 国产精品剧情在线亚洲| 国产一区二区三区电影在线观看 | 99精彩视频在线观看免费| 欧洲一区二区三区在线| 日韩一区欧美二区| 久久爱.com| 日本不卡1区2区3区| 国产高清在线一区二区| 欧美va在线播放| 91日韩一区二区三区| 妖精视频一区二区三区免费观看| 黄色在线网站| 日韩成人午夜影院| 色综合五月天导航| 欧洲av一区二区嗯嗯嗯啊| 久久精品国产免费看久久精品| 亚洲1区在线观看| 国产中文字幕在线播放| 亚洲日本japanese丝袜| 久久国产一区二区三区| 亚洲r级在线视频| 媚黑女一区二区| www.久久99| av在线免费观看网| 奇米影视亚洲色图| 91香蕉电影院| 自拍亚洲一区欧美另类| 性久久久久久久久| 国产传媒一区在线| 日韩国产欧美| 两个人看的在线视频www| 91av入口| 国产精品美女在线播放| 97国产suv精品一区二区62| 欧美亚洲一区二区在线观看| 成人综合在线视频| 欧美成人直播| 久久精品嫩草影院| 日本不卡视频| 69免费视频| 69sex久久精品国产麻豆| av一区二区三区四区电影| 久久av中文字幕| 精品国产123| 色综合天天综合狠狠|