欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue usePop彈窗控制器的實現(xiàn)

 更新時間:2023年04月17日 14:27:42   作者:copyLeft  
本文主要介紹了vue usePop彈窗控制器的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

當UI庫彈窗無法滿足自定義需求時,需要我們自己開發(fā)簡單的彈窗組件。彈窗組件與普通業(yè)務組件開發(fā)沒有太大區(qū)別,重點在多彈窗之間的關系控制。例如: 彈窗1,彈窗2 由于觸發(fā)時機不同,需要不同的層疊關系,后觸發(fā)的始終在最前端,點擊彈窗頭改變層疊關系。 單一彈窗多處調用等。這里封裝基礎的管理鉤子,簡化這些問題的處理。

功能目標

  • 單例,多例彈窗
  • 可配置彈窗自定義參數(shù)
  • 可接收彈窗自定義事件
  • 層級控制
  • 自定義定位

該鉤子的目的主要為了處理彈窗之間的控制關系,具體如何渲染交由調用方

快速使用

// 主容器
import { usePopContainer, buildDefaultPopBind, position } from '@/hooks/usePop'
import UserInfoPop form './UserInfoPop.vue'
// 快捷工具,將內部鉤子通過依賴注入,共享給子組件
const [popMap, popTools] = usePopContainer()
const popBind = buildDefaultPopBind(popTools, popTools.componentsCache)


const userPop = popBind('userInfo', UserInfoPop, {
  position: { // 組件定位
    top: 200
  },
  userId: 'xxx', // 組件porps
  @close(){ // 組件事件
    console.log('close')
  }
})


// 調用
userPop.open()
setTimeout(userPop.close, 1000 * 3)




// template
<template v-for="(pop, popId) of popMap">
  // 渲染彈窗列表
   <component
     :is="pop.component"
     :key="popId"
     v-bind="pop.props"
     v-on="pop.on"
   >
   </component>
</template>

多處調用

同一彈窗,多實例 add

// 容器注冊
const [popMap, popTools] = usePopContainer()
// 新增彈窗1
popTools.add(popId1, {
   component: UserPop, // 彈窗組件
   useId: 'xxx', // 彈窗Props
   '@close': () => { ... } //彈窗事件
})


// 新增彈窗2
popTools.add(popId2, {
   component: UserPop, // 彈窗組件
   useId: 'xxx', // 彈窗Props
   '@close': () => { ... } //彈窗事件
})
// 覆蓋彈窗1
// popId 為彈窗唯一標識, 如果popId相同,組件配置將被替換
popTools.add(popId1, {
   component: UserPop, // 彈窗組件
   useId: 'yyy', // 彈窗Props
   '@close': () => { ... } //彈窗事件
})

所有彈窗都通過popId,查找or判斷唯一性。

配置參數(shù):以@ 開頭的都將組為組件的事件被綁定, 除了 @[事件名] component 其他屬性都將作為props,包括 style 等屬性

移除 remove

const [popMap, popTools] = usePopContainer()
popTools.add(popId, {
   component: UserPop, // 彈窗組件
   useId: 'xxx', // 彈窗Props
   '@close': () => { ... } //彈窗事件
})
// 移除
popTools.remove(popId)

替換 replace

// 主容器
const [popMap, popTools] = usePopContainer()


// 子組件A
popTools.replace(popId, {
   component: UserPop, // 彈窗組件
   useId: 'xxx', // 彈窗Props
   '@close': () => { ... } //彈窗事件
})


// 子組件B
popTools.replace(popId, {
   component: UserPop, // 彈窗組件
   useId: 'xxx', // 彈窗Props
   '@close': () => { ... } //彈窗事件
})

當有多處調用同一彈窗,而只需要最新的觸發(fā)彈窗時,使用 replace. 該方法其實就是 remove add 的包裝方法

更新 update

const [popMap, popTools] = usePopContainer()
popTools.replace(popId, {
   component: UserPop, // 彈窗組件
   useId: 'xxx', // 彈窗Props
   '@close': () => { ... } //彈窗事件
})
// 更新參數(shù)
popTools.update(popId, {
   useId: 'yyy'

})

通過popId 查詢彈窗,將新傳入的參數(shù)與原配置做合并

預注冊 componentsCache

const [popMap, popTools] = usePopContainer()
// 局部預先注冊
// 注冊只是預先緩存
popTools.componentsCache.add(popId, {
  component: UserPop,
  id: 'xxx',
  '@cloes': () => {...}
})
// 調用
popTools.add(popId, { component: popId })
// of
popTools.replace(popId, { component: popId })
// add將從componentsCache查詢預注冊配置

除了局部緩存, componentsCache, 模塊還導出了 globalComponentsCache 全局公共緩存。

依賴注入

為了方便父子組件調用,提供了usePopContainer usePopChildren 方法,

// 父組件
const [popMap, popTools] = usePopContainer()
// 子組件
const { popTools } = usePopChildren()
popTools.add({
   ...
})

函數(shù)接收依賴注入標識, 為傳入標識時,使用默認標識

usePop 工具函數(shù)

  • add(popId, options) 創(chuàng)建彈窗
  • update(popId, options) 更新彈窗配置(定位, props,events)
  • remove(popId) 移除彈窗
  • replace(popId, options) 替換,如果多處調用同一彈窗,希望只顯示唯一同類彈窗時,

 使用該函數(shù),多個彈窗公用相同的popId

  • clearAllPop() 清空所有彈窗
  • updateIndex(popId) 更新彈窗層級
  • downIndex(popId) 層級下降一級
  • topIndex(popId) 層級置頂

core 實現(xiàn)

import { shallowRef, unref, provide, inject } from 'vue'
import { merge } from 'lodash-es'
import { splitProps, counter } from './utils'


export const DEFAULT_POP_SIGN = 'DEFAULT_POP_SIGN'


// 全局層級累加器
export const counterStore = counter()


/**
 * 預先pop注冊表
 * @summary
 * 便捷多處pop調用, 調用pop顯示方法時,
 * 直接通過名稱查詢對應的組件預設
 * 將調用與事件配置解耦
 * @returns
 */
function componentsRegistry () {
  let componentsCache = new Map([])


  function has (componentName) {
    return componentsCache.has(componentName)
  }


  function add (componentName, options) {
    componentsCache.set(componentName, options)
  }


  function remove (componentName) {
    if (has(componentName)) {
      componentsCache.delete(componentName)
    }
  }


  function fined (componentName) {
    return componentsCache.get(componentName)
  }


  function clear () {
    componentsCache = new Map([])
  }


  function getComponents () {
    return [...componentsCache.values()]
  }


  function getComponentNames () {
    return [...componentsCache.keys()]
  }


  return {
    has,
    add,
    remove,
    fined,
    clear,
    getComponents,
    getComponentNames
  }
}


export const globalComponentsCache = componentsRegistry()


/**
 * 彈窗控制器
 * @summary
 * 提供多彈窗控制邏輯:
 * 1. 單例, 多例: 通過不同的 popId 控制彈窗實例的個數(shù)
 * 2. 參數(shù)接收: open接收初始傳給pop的事件和參數(shù)配置, update 提供參數(shù)更新
 * 3. 事件回調: options 配置屬性 { @[事件名稱]:事件回調 } 將作為事件綁定到pop上
 * 4. 動態(tài)疊加: 內部將為組件配置 zIndex, 組件內需要自定義接收該參數(shù),判斷如何處理層疊關系
 * 5. 定位: 定位需要彈窗組件接收 position props 內部綁定樣式
 *
 * @tips
 *  這里定位為了兼容 useMove做了接口調整,原接口直接輸出定位樣式。當前出position屬性,
 *  組件內需要自行處理定位樣式。 這里存在 style 合并和透傳的的問題, 通過透傳的style與
 *  props 內定義的style將分開處理, 即最終的結果時兩個style的集合, 且透傳的style優(yōu)先級高于
 *  prop。所以如果直出定位樣式,通過透傳綁定給彈窗組件,后續(xù)的useMove拖拽樣式將始終被透傳樣式覆蓋
 *
 * @api
 * - add(popId, options) 創(chuàng)建彈窗
 * - update(popId, options) 更新彈窗配置(定位, props,events)
 * - remove(popId) 移除彈窗
 * - replace(popId, options) 替換,如果多處調用同一彈窗,希望只顯示唯一同類彈窗時,
 *  使用該函數(shù),多個彈窗公用相同的popId
 * - clearAllPop() 清空所有彈窗
 * - updateIndex(popId) 更新彈窗層級
 * - downIndex(popId) 層級下降一級
 * - topIndex(popId) 層級置頂
 *
 * @example01 - 一般使用
 *
 * const [
 *  pops,
 *  popTools
 * ]  = usePop()
 *
 *
 * // 容器組件
 * <component
 *  v-for='(pop, popId) of pops'
 *  :is='pop'
 *  v-bind='pop.props' // 接收定位樣式
 *  v-on='pop.on' // 接收回調事件
 *  :key='popId'>
 * </component>
 *
 * // 調用彈窗
 * popTools.add('popId', {
 *  component: POP, // 彈窗組件
 *  position: { top: 200 } // 彈窗定位
 *  title: 'xxx', // 彈窗自定義props
 *  @click(e){  // 彈窗事件
 *     ....
 *  }
 * })
 *
 *
 * @example02 - 預注冊
 * 通過預注冊組件,再次調用時,只需要傳入對應注冊名稱,而不需要具體的配置項
 * const [ pops, popTools ] = usePop()
 *
 * // 注冊本地彈窗
 * popTools.componentsCache.add('userInfo', {
 *  component: CMP,
 *  opsition: { ... }
 *  ...
 * })
 *
 * // 調用
 * popTools.add('userInfo', { component: 'userInfo' })
 *
 */
export function usePop () {
  const components = shallowRef({})
  const componentsCache = componentsRegistry()


  function has (popId) {
    return !!unref(components)[popId]
  }


  /**
   * 添加pop
   * @param popId
   * @param options
   * @returns
   */
  function add (popId, options = {}) {
    if (has(popId)) {
      return false
    }


    let {
      component,
      ..._options
    } = options


    // 全局緩存
    if (globalComponentsCache.has(component)) {
      const { component: cacheComponents, ...cacheOptions } = globalComponentsCache.fined(component)
      component = cacheComponents
      _options = { ...cacheOptions, ..._options }
    }


    // 局部緩存
    if (componentsCache.has(component)) {
      const { component: cacheComponents, ...cacheOptions } = componentsCache.fined(component)
      component = cacheComponents
      _options = { ...cacheOptions, ..._options }
    }


    counterStore.add()
    const newOptions = splitProps({ ..._options, zIndex: counterStore.getCount() })


    components.value = {
      ...components.value,
      [popId]: {
        popId,
        component,
        ...newOptions
      }
    }
  }


  /**
   * 更新組件參數(shù)
   * @param {*} popId
   * @param {*} options
   * @returns
   */
  function update (popId, options = {}) {
    if (!has(popId)) {
      return false
    }


    const { component, ...oldOptions } = components.value[popId]
    const newOptions = splitProps(options)
    components.value = {
      ...components.value,
      [popId]: {
        component,
        ...merge(oldOptions, newOptions)
      }
    }
  }


  /**
   * 移除pop
   * @param popId
   */
  function remove (popId) {
    if (has(popId)) {
      const newCmp = components.value
      delete newCmp[popId]
      components.value = {
        ...newCmp
      }
    }
  }


  /**
   * 多處調用同一pop時, 替換原顯示pop。
   * @param popId
   * @param options
   */
  function replace (popId, options) {
    remove(popId)
    add(popId, options)
  }


  function clearAllPop () {
    components.value = {}
  }


  /**
  * 向上一層級
  * @param popId
  * @returns
  */
  function updateIndex (popId) {
    if (!has(popId)) {
      return
    }
    const currentComponent = unref(components)[popId]
    const upComponent = Object.values(unref(components)).fined(i => i.zIndex > currentComponent.zIndex)
    const currentIndex = currentComponent.zIndex
    const upIndex = upComponent.zIndex
    update(currentIndex.popId, {
      zIndex: upIndex
    })
    update(upComponent.popId, {
      zIndex: currentIndex
    })
  }


  /**
   * 向下一層級
   * @param {*} popId
   * @returns
   */
  function downIndex (popId) {
    if (!has(popId)) {
      return
    }
    const currentComponent = unref(components)[popId]
    const upComponent = Object.values(unref(components)).fined(i => i.zIndex < currentComponent.zIndex)
    const currentIndex = currentComponent.zIndex
    const upIndex = upComponent.zIndex
    update(currentIndex.popId, {
      zIndex: upIndex
    })
    update(upComponent.popId, {
      zIndex: currentIndex
    })
  }


  /**
   * 頂層
   * @param popId
   * @returns
   */
  function topIndex (popId) {
    if (!has(popId)) {
      return
    }
    counterStore.add()
    update(popId, {
      zIndex: counterStore.getCount()
    })
  }


  return [    components,    {      has,      add,      remove,      update,      replace,      clearAllPop,      topIndex,      updateIndex,      downIndex,      componentsCache    }  ]
}


/**
 * 嵌套結構下的彈窗鉤子
 */


// 容器鉤子
export function usePopContainer (provideKey = DEFAULT_POP_SIGN) {
  const [popMap, popTools] = usePop()
  provide(
    provideKey,
    {
      popTools
    }
  )
  return [    popMap, popTools  ]
}


// 子容器鉤子
export function usePopChildren (provideKey = DEFAULT_POP_SIGN) {
  return inject(provideKey, {})
}

core utils

export function isEvent (propName) {
  const rule = /^@/i
  return rule.test(propName)
}

// @click => click
export function eventNameTransition (name) {
  return name.replace('@', '')
}

// 拆分事件與屬性
export function splitProps (cmpProps) {
  return Object.entries(cmpProps).reduce((acc, [propName, propValue]) => {
    if (isEvent(propName)) {
      // 自定義事件
      acc.on[eventNameTransition(propName)] = propValue
    } else {
      acc.props[propName] = propValue
    }

    return acc
  }, { on: {}, props: {} })
}

export function counter (initCount = 0, step = 1) {
  let count = initCount

  function add (customStep) {
    count += customStep || step
  }

  function reduce (customStep) {
    count -= customStep || step
  }

  function reset (customStep) {
    count = customStep || initCount
  }

  function getCount () {
    return count
  }

  return {
    add,
    reduce,
    reset,
    getCount
  }
}

工具

import { merge } from 'lodash-es'

/**
 * 注冊并返回彈窗快捷方法
 * @param {*} popTools
 * @returns
 */
export function buildDefaultPopBind (popTools, componentsCache) {
  return (popId, component, options) => {
    componentsCache.add(popId, {
      component,
      // 默認定位
      position: position(),
      ...bindDefaultEvents(popTools, popId),
      ...options
    })


    return {
      open (options) {
        popTools.add(popId, { component: popId, ...options })
      },
      close () {
        popTools.remove(popId)
      },
      update (options) {
        popTools.update(popId, { component: popId, ...options })
      },
      replace (options) {
        popTools.replace(popId, { component: popId, ...options })
      }
    }
  }
}


export const DEFAULT_POSITION = {
  top: 240,
  left: 0,
  right: 0
}


export function position (options = DEFAULT_POSITION) {
  return merge({}, DEFAULT_POSITION, options)
}


export function bindDefaultEvents (popTools, popId) {
  return {
    '@headerMousedown' () {
      popTools.topIndex(popId)
    },
    '@close' (e) {
      popTools.remove(popId)
    }
  }
}

 到此這篇關于vue usePop彈窗控制器的實現(xiàn)的文章就介紹到這了,更多相關vue usePop彈窗控制器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 深入理解Vue3里的EffectScope

    深入理解Vue3里的EffectScope

    本文主要介紹了Vue3里的EffectScope,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • 詳解在vue中如何使用node.js

    詳解在vue中如何使用node.js

    這篇文章主要給大家介紹了關于在vue中如何使用node.js的相關資料,vue和nodejs經常讓新手們感到困惑,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-07-07
  • Vue3中操作dom的四種方式總結(建議收藏!)

    Vue3中操作dom的四種方式總結(建議收藏!)

    VUE是通過傳遞一些配置給Vue對象和頁面中引用插值表達式來操作DOM的,下面這篇文章主要給大家介紹了關于Vue3中操作dom的四種方式總結,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-12-12
  • mini-vue渲染的簡易實現(xiàn)

    mini-vue渲染的簡易實現(xiàn)

    本文主要介紹了mini-vue渲染的簡易實現(xiàn),主要簡單來實現(xiàn)一個虛擬dom渲染真實dom,以及更新的方法。具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • VUE中v-on:click事件中獲取當前dom元素的代碼

    VUE中v-on:click事件中獲取當前dom元素的代碼

    這篇文章主要介紹了VUE中v-on:click事件中獲取當前dom元素的代碼,文中同時給大家提到了v-on:click獲取當前事件對象元素的方法,需要的朋友可以參考下
    2018-08-08
  • Pure admin-Router標簽頁配置與頁面持久化實現(xiàn)方法詳解

    Pure admin-Router標簽頁配置與頁面持久化實現(xiàn)方法詳解

    這篇文章主要介紹了Pure admin-Router標簽頁配置與頁面持久化實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-01-01
  • 解決VUEX刷新的時候出現(xiàn)數(shù)據(jù)消失

    解決VUEX刷新的時候出現(xiàn)數(shù)據(jù)消失

    這篇文章主要介紹了解決VUEX刷新的時候出現(xiàn)數(shù)據(jù)消失,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Ant Design的可編輯Tree的實現(xiàn)操作

    Ant Design的可編輯Tree的實現(xiàn)操作

    這篇文章主要介紹了Ant Design的可編輯Tree的實現(xiàn)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • vue中組件如何使用vue-quill-editor

    vue中組件如何使用vue-quill-editor

    這篇文章主要介紹了vue中組件如何使用vue-quill-editor問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Vue實現(xiàn)項目部署到非根目錄及解決刷新頁面時找不到資源

    Vue實現(xiàn)項目部署到非根目錄及解決刷新頁面時找不到資源

    這篇文章主要介紹了Vue實現(xiàn)項目部署到非根目錄及解決刷新頁面時找不到資源問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03

最新評論