最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue自定義render統(tǒng)一項目組彈框功能

 更新時間:2020年06月07日 13:22:02   作者:JS強迫癥患者  
這篇文章主要介紹了Vue自定義render統(tǒng)一項目組彈框功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、本文收獲

pick

二、為什么要統(tǒng)一封裝彈框;

要封裝成怎樣

通過舉例常規(guī)彈框的寫法。我們可以體會到,通常要彈出一個頁面,需要創(chuàng)建一個頁面 normalDialog.vue 包裹 dialogBody.vue (彈框主體);需要 parent.vue 設置flag控制彈框顯示隱藏, normalDialog.vue 關閉的時候設置 parent.vue 對應 flag 。缺點: 流程繁雜、配置繁瑣、不靈活、樣式不統(tǒng)一和參數(shù)傳遞麻煩等 。如果一個項目彈框較多的時候,弊端將會更明顯,大量的 isXxxDialogShow ,大量的 vue 文件。因此項目組急需一個能簡單配置就能彈出彈框的 API 。

1. 常規(guī)彈框?qū)懛?dialoBody.vue (彈框主體) ,此處采用 Composition API 的寫法。只做了簡單的頁面,包含校驗,抽取保存數(shù)據(jù)的常規(guī)邏輯。

<template>
 <div class="dialog-body">
 <div class="item">
 <div>名稱</div>
 <el-input v-model="name"></el-input>
 </div>
 <div class="item">
 <el-radio-group v-model="attention">
 <el-radio label="已關注"></el-radio>
 <el-radio label="等下關注"></el-radio>
 </el-radio-group>
 </div>
 <div class="item">
 <el-radio-group v-model="like">
 <el-radio label="已點贊"></el-radio>
 <el-radio label="等下點贊"></el-radio>
 </el-radio-group>
 </div>
 </div>
</template>

<script>
import { reactive, toRefs } from '@vue/composition-api'
import pick from 'lodash/pick'
import { Message } from 'element-ui'

export default {
 props: {
 defaultName: String,
 },
 setup(props, ctx) {
 const ATTENTIONED = '已關注'
 const LIKED = '已點贊'
 const state = reactive({
 name: props.defaultName, // 名稱
 attention: '已關注', // 關注
 like: '已點贊', // 點贊
 })
 /*************************************************************
 * 頁面綁定的事件
 * 建議寫法:
 * 1. 定義methods常量
 * 2. 處理相關業(yè)務邏輯的時候,需要綁定事件到頁面的時
 * 建議通過methods.onXxx = ()=>{ // 相關邏輯 }的形式定義
 * 好處1: onXxx定義的位置和相關業(yè)務邏輯代碼關聯(lián)一起
 * 好處2: 可以統(tǒng)一通過...methods的形式在setup統(tǒng)一解構(gòu)
 * 好處3: 當頁面邏輯復雜,需要操作的數(shù)據(jù)關聯(lián)性強,不可拆解組件;
 *  可將相關業(yè)務的代碼在獨立模塊定義;
 *  獨立模塊暴露API handleXxx(methods,state),流水線加工methods;
 *  和Vue2源碼一樣,流水線加工的思想.
 */
 const methods = {}
 // 校驗名稱
 methods.onNameBlur = () => {}

 // ************************ 向外暴露的API ************************
 const apiMethods = {
 // 保存前校驗
 isCanSave() {
 if (state.attention !== ATTENTIONED || state.like !== LIKED) {
  Message.error('未關注或者點贊,不能關閉,嘻嘻')
  return false
 }
 return true
 },
 // 獲取保存數(shù)據(jù)
 getSaveData() {
 // ******* lodash pick 從對象中抽取數(shù)據(jù)
 return pick(state, ['name', 'attention', 'like'])
 },
 }
 return {
 ...toRefs(state),
 ...methods,
 apiMethods,
 }
 },
}
</script>

<style lang="less">
.dialog-body {
 width: 100%;
 height: 100px;
}
</style>

2.normalDialog.vue 包裹彈框主體 dialoBody.vue

<template>
 <el-dialog 
 title="帥哥,美女,我是標題" 
 :visible.sync="isShow" 
 width="30%" 
 :before-close="onClose"
 >
 <dialog-body default-name="參數(shù)傳遞的名稱" ref="inner"></dialog-body>
 <span slot="footer" class="dialog-footer">
 <el-button @click="onClose">取 消</el-button>
 <el-button type="primary" @click="onOK">確 定</el-button>
 </span>
 </el-dialog>
</template>

<script>
import dialogBody from './dialogBody.vue'
export default {
 components: {
 dialogBody,
 },
 data() {
 return {
 isShow: true,
 }
 },
 methods: {
 onClose() {
 // *********** 修改parent.vue ********
 this.$parent.isNormalDialogShow = false
 },
 // ******* 控制保存流程 ********
 onOK() {
 const inner = this.$refs.inner
 // 校驗是否可以保存
 if (inner.apiMethods.isCanSave()) {
 // 獲取保存數(shù)據(jù)
 const postData = inner.apiMethods.getSaveData()
 console.log('>>>>> postData >>>>>', postData)
 // 保存成功后關閉彈框
 this.onClose()
 }
 },
 },
}
</script>

parent.vue

// html 部分
<normal-dialog v-if="isNormalDialogShow" />

// Js部分
data(){
	isNormalDialogShow:false
}
methods:{
 onDialogShow(){ // ******控制彈框顯示*****
 this.isNormalDialogShow = true
 }
}

2. 要封裝成怎樣

2.1 API訴求:

isXxxDialogShow
el-dialog

2.2 理想API:

import dialogBody from './dialogBody.vue'
const dialog = new JSDialog({
 comonent: dialogBody, 
 dialogOpts: { // 可擴展配置
 title: 'JSDialog設置的彈框標題',
 width: '400px'
 },
 props: {
 defaultName: 'JSDialog傳遞的參數(shù)',
 },
 onOK() {
 const inner = dialog.getInner() // 能取到dialogBody的引用
 // 控制流程
 if (inner.apiMethods.isCanSave()) {
 // 獲取保存數(shù)據(jù)
 const postData = inner.apiMethods.getSaveData()
 console.log('>>>>> postData >>>>>', postData)
 // 關閉彈框
 dialog.close()
 }
 },
 onCancel() {
 dialog.close() // 彈框關閉
 },
})
dialog.show() // 彈框顯示

三、如何封裝

動態(tài)控制顯示內(nèi)容,腦海浮現(xiàn)的三個方案: 卡槽、動態(tài)組件和重寫 render 。下面在動態(tài)彈框場景下簡單對比三個方案。

  • slot(卡槽) ,和 el-dialog 原理類似,只是再封裝了一層,少定義了 normalDialog.vue 文件。 缺點:調(diào)用復雜,不靈活;不容易控制關閉的流程;只能在 template 中定義 。
  • component(動態(tài)組件) ,創(chuàng)建 commonDialog.vue ,統(tǒng)一掛在 App.vue 下,利用 <component :is="componentId"></component> 動態(tài)切換彈框主體, commonDialog.vue 監(jiān)聽 componentId 變化來切換彈框主體。 缺點:要提前將所有彈框主體組件注冊到commonDialog.vue頁面的components上;依賴于vuex,侵入性較強;純js文件通過vuex彈出彈框相對復雜,不靈活 。
  • 重寫 render , render 是 Vue 對造輪子開發(fā)者開放的后門。動態(tài)彈框可作為獨立的功能模塊,內(nèi)部通過new Vue ,重寫 render 控制渲染內(nèi)容。 獨立 Vue 實例,可預先創(chuàng)建,可在任何位置控制彈框,靈活,清晰 。 缺點:暫無

1. 整體代碼

先整體預覽一下代碼,下面再細分講解。

import Vue from 'vue'
import merge from 'lodash/merge'
import orderBy from 'lodash/orderBy'

// 按鈕配置項構(gòu)造器
function btnBuilder(options) {
 const defaultBtn = {
 text: '按鈕', // 顯示文本
 clickFn: null, // 點擊回調(diào)
 type: 'default', // 樣式
 isHide: false, // 是否隱藏
 order: 2 // 順序
 }
 return { ...defaultBtn, ...options }
}

export default class JSDialog {
 constructor(originOptions) {
 this.options = {}
 this.vm = null
 this._mergeOptions(originOptions)
 this._initVm()
 }
 // 參數(shù)合并
 _mergeOptions(originOptions) {
 const defaultOptions = {
 component: '', // 彈框主體vue頁面
 // 可擴展el-dialog官方api所有配置項,小駝峰aaaBbbCcc
 dialogOpts: {
 width: '40%',
 title: '默認標題'
 },
 // 傳入彈框主體vue組件的參數(shù)
 props: {},
 // 點擊確定回調(diào)
 onOK: () => {
 console.log('JSDialog default OK'), this.close()
 },
 // 點擊取消回調(diào)
 onCancel: () => {
 console.log('JSDialog default cancel'), this.close()
 },
 footer: {
 ok: btnBuilder({
  text: '確定',
  type: 'primary',
  order: 0
 }),
 cancel: btnBuilder({
  text: '取消',
  order: 1
 })
 }
 }
 // 參數(shù)合并到this.options
 merge(this.options, defaultOptions, originOptions)
 const footer = this.options.footer
 Object.entries(footer).forEach(([key, btnOptions]) => {
 // 確定和取消默認按鈕
 if (['ok', 'cancel'].includes(key)) {
 const clickFn = key === 'ok' ? this.options.onOK : this.options.onCancel
 // 默認按鈕回調(diào)優(yōu)先級: footer配置的clickFn > options配置的onOK和onCancel
 btnOptions.clickFn = btnOptions.clickFn || clickFn
 } else {
 // 新增按鈕
 // 完善配置
 footer[key] = btnBuilder(btnOptions)
 }
 })
 }
 _initVm() {
 const options = this.options
 const beforeClose = this.options.footer.cancel.clickFn // 彈框右上角關閉按鈕回調(diào)
 this.vm = new Vue({
 data() {
 return {
  // 需要響應式的數(shù)據(jù)
  footer: options.footer, // 底部按鈕
  visible: false // 彈框顯示及關閉
 }
 },
 methods: {
 show() {
  // 彈框顯示
  this.visible = true
 },
 close() {
  // 彈框關閉
  this.visible = false
 },
 clearVm() {
  // 清除vm實例
  this.$destroy()
 }
 },
 mounted() {
 // 掛載到body上
 document.body.appendChild(this.$el)
 },
 destroyed() {
 // 從body上移除
 document.body.removeChild(this.$el)
 },
 render(createElement) {
 // 彈框主體
 const inner = createElement(options.component, {
  props: options.props, // 傳遞參數(shù)
  ref: 'inner' // 引用
 })
 // 控制按鈕顯示隱藏
 const showBtns = Object.values(this.footer).filter(btn => !btn.isHide)
 // 控制按鈕順序
 const sortBtns = orderBy(showBtns, ['order'], ['desc'])
 // 底部按鈕 jsx 寫法
 const footer = (
  <div slot="footer">
  {sortBtns.map(btn => (
  <el-button type={btn.type} onClick={btn.clickFn}>
  {btn.text}
  </el-button>
  ))}
  </div>
 )
 // 彈框主體
 const elDialog = createElement(
  'el-dialog',
  {
  // el-dialog 配置項
  props: {
  ...options.dialogOpts,
  visible: this.visible,
  beforeClose
  },
  // **** 看這里,visible置為false后,el-dialog銷毀后回調(diào) *****
  on: {
  closed: this.clearVm
  },
  ref: 'elDialog'
  },
  // 彈框內(nèi)容:彈框主體和按鈕
  [inner, footer]
 )
 return elDialog
 }
 }).$mount()
 }
 // 封裝API
 // 關閉彈框
 close() {
 this.vm.close()
 }
 // 顯示彈框
 show() {
 this.vm.show()
 }
 // 獲取彈框主體實例,可訪問實例上的方法
 getInner() {
 return this.vm.$refs.inner
 }
}

2. 參數(shù)合并

​ 要做到 API 訴求中的:調(diào)用簡單、傳參簡便和可擴展控制彈框樣式。參數(shù)合并便是 成本最小 的實現(xiàn)方案,配合 TS 效果更佳。定義默認參數(shù),通過 lodash 的 merge ,合并深層屬性。通過參數(shù)合并還能做到自定義 footer 按鈕,控制文本,樣式,順序和執(zhí)行回調(diào)。

// 參數(shù)合并
_mergeOptions(originOptions) {
 const defaultOptions = {
 component: '', // 彈框主體vue頁面
 // 可擴展el-dialog官方api所有配置項,小駝峰aaaBbbCcc
 dialogOpts: {
 width: '40%',
 title: '默認標題'
 },
 // 傳入彈框主體vue組件的參數(shù)
 props: {},
 // 點擊確定回調(diào)
 onOK: () => {
 console.log('JSDialog default OK'), this.close()
 },
 // 點擊取消回調(diào)
 onCancel: () => {
 console.log('JSDialog default cancel'), this.close()
 },
 footer: {
 ok: btnBuilder({
 text: '確定',
 type: 'primary',
 order: 0
 }),
 cancel: btnBuilder({
 text: '取消',
 order: 1
 })
 }
 }
 // 參數(shù)合并到this.options
 merge(this.options, defaultOptions, originOptions)
 const footer = this.options.footer
 Object.entries(footer).forEach(([key, btnOptions]) => {
 // 確定和取消默認按鈕
 if (['ok', 'cancel'].includes(key)) {
 const clickFn = key === 'ok' ? this.options.onOK : this.options.onCancel
 // 默認按鈕回調(diào)優(yōu)先級: footer配置的clickFn > options配置的onOK和onCancel
 btnOptions.clickFn = btnOptions.clickFn || clickFn
 } else { // 新增按鈕
 // 完善配置
 footer[key] = btnBuilder(btnOptions)
 }
 })
}

3. render函數(shù)

​ 摘取一段 渲染函數(shù) & JSX 官方文檔關于 render 的描述: Vue 推薦在絕大多數(shù)情況下使用模板來創(chuàng)建你的 HTML。然而在一些場景中,你真的需要 JavaScript 的完全編程的能力。這時你可以用 渲染函數(shù) ,它比模板更接近編譯器。 ​ ​ 官方文檔對渲染函數(shù)的寫法,參數(shù),對應JSX寫法介紹已經(jīng)很詳細,這里就不再贅述。下面代碼是在最新vue-cli創(chuàng)建項目上運行的,嘗試了JS參數(shù)創(chuàng)建元素和JSX創(chuàng)建元素兩種寫法。

render(createElement) {
 // 彈框主體
 const inner = createElement(options.component, {
 props: options.props, // 傳遞參數(shù)
 ref: 'inner' // 引用
 })
 // 控制按鈕顯示隱藏
 const showBtns = Object.values(this.footer).filter(btn => !btn.isHide)
 // 控制按鈕順序
 const sortBtns = orderBy(showBtns, ['order'], ['desc'])
 // 底部按鈕 jsx 寫法
 const footer = (
 <div slot="footer">
 {sortBtns.map(btn => (
 <el-button type={btn.type} onClick={btn.clickFn}>
  {btn.text}
 </el-button>
 ))}
 </div>
 )
 // 彈框主體
 const elDialog = createElement(
 'el-dialog',
 {
 // el-dialog 配置項
 props: {
 ...options.dialogOpts,
 visible: this.visible
 },
 on: {
 closed: this.clearVm
 },
 ref: 'elDialog'
 },
 // 彈框內(nèi)容:彈框主體和按鈕
 [inner, footer]
 )
 return elDialog
}

4. 封裝API

​ 暫時只封裝了三個 API ,可根據(jù)不同的場景擴展 API ,比如彈框不銷毀隱藏,彈框刷新等。

show() ,彈框顯示

顯示主要是修改 el-dialog 的 visible 為 true ,控制掛載到 body 上的彈框顯示。

show() {
 this.vm.show()
}

close() ,彈框關閉

關閉處理流程:修改 el-dialog 的 visible 為 false ;觸發(fā) el-dialog 的 closed 事件;執(zhí)行 clearVm ;執(zhí)行 vm 的 $destroy() ; destroyed() 回調(diào)中將 $el 從 body 中移除。

close() {
 this.vm.close()
}

getInner() ,獲取彈框主體實例,可用于訪問實例上的方法,控制按鈕流程

getInner() {
 return this.vm.$refs.inner
}

四、如何使用

1. 最簡單場景,只配置頁面

按鈕事件回調(diào)采用默認的回調(diào),確定和取消按鈕都可關閉彈框

import dialogBody from './renderJsx/dialogBody'
const dialog = new JSDialog({
 component: dialogBody,
})
dialog.show() // 彈框顯示

效果如下:

 

2. 控制彈框樣式及確定流程

可自定義el-dialog支持的配置項,見 Dialog 對話框 ;比如:title、 customClass 。通過customClass可統(tǒng)一控制項目內(nèi)彈框的風格;可控制確定取消按鈕代碼回調(diào)。

import dialogBody from './renderJsx/dialogBody'
const dialog = new JSDialog({
 component: dialogBody,
 dialogOpts: {
 title: '靚仔,美女歐嗨呦',
 customClass:'js-dialog'
 },
 props: {
 defaultName: 'JSDialog傳遞的參數(shù)'
 },
 onOK() {
 const inner = dialog.getInner() // 能取到dialogBody的引用
 // 控制流程
 if (inner.apiMethods.isCanSave()) {
  // 獲取保存數(shù)據(jù)
  const postData = inner.apiMethods.getSaveData()
  console.log('>>>>> postData >>>>>', postData)
  // 關閉彈框
  dialog.close()
 }
 },
 onCancel() {
 dialog.close() // 彈框關閉
 }
})

效果如下:

 

3. 自定義footer

自定義按鈕可控制執(zhí)行回調(diào),樣式,順序,顯示與隱藏

import dialogBody from './renderJsx/dialogBody'
const dialog = new JSDialog({
 component: dialogBody,
 footer: {
 ok: { // 修改默認按鈕
  text: '新增'
 },
 cancel: { // 隱藏默認按鈕
  isHide: true
 },
 add: { // 新增按鈕
  text: '另存為',
  clickFn() {
  dialog.close()
  },
  order: -1 // 控制按鈕順序,order小的顯示在右邊
 },
 add2: {
  text: '新增按鈕2',
  clickFn() {
  dialog.close()
  },
  order: 3
 }
 }
})
dialog.show() // 彈框顯示

效果如下:

總結(jié)

到此這篇關于Vue自定義render統(tǒng)一項目組彈框功能的文章就介紹到這了,更多相關Vue自定義render項目組彈框內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • VSCode Vue開發(fā)推薦插件和VSCode快捷鍵(小結(jié))

    VSCode Vue開發(fā)推薦插件和VSCode快捷鍵(小結(jié))

    這篇文章主要介紹了VSCode Vue開發(fā)推薦插件和VSCode快捷鍵(小結(jié)),文中通過圖文表格介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • vue簡易記事本開發(fā)詳解

    vue簡易記事本開發(fā)詳解

    這篇文章主要為大家詳細介紹了vue簡易記事本的開發(fā)過程,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 在vue中v-bind使用三目運算符綁定class的實例

    在vue中v-bind使用三目運算符綁定class的實例

    今天小編就為大家分享一篇在vue中v-bind使用三目運算符綁定class的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • Vue組件通信方式(父傳子、子傳父、兄弟通信)

    Vue組件通信方式(父傳子、子傳父、兄弟通信)

    這篇文章主要介紹了Vue組件通信方式(父傳子、子傳父、兄弟通信),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Vue項目如何實現(xiàn)rsa加密

    Vue項目如何實現(xiàn)rsa加密

    這篇文章主要介紹了Vue項目如何實現(xiàn)rsa加密,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Vue中的Object.defineProperty全面理解

    Vue中的Object.defineProperty全面理解

    這篇文章主要介紹了Vue中的Object.defineProperty全面理解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 如何解決element-ui中多個table在tab切換時出現(xiàn)寬度縮小問題

    如何解決element-ui中多個table在tab切換時出現(xiàn)寬度縮小問題

    這篇文章主要介紹了如何解決element-ui中多個table在tab切換時出現(xiàn)寬度縮小問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue父子組件的嵌套的示例代碼

    vue父子組件的嵌套的示例代碼

    本篇文章主要介紹了vue父子組件的嵌套的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 使用VUE+iView+.Net Core上傳圖片的方法示例

    使用VUE+iView+.Net Core上傳圖片的方法示例

    這篇文章主要介紹了使用VUE+iView+.Net Core上傳圖片的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • vuex數(shù)據(jù)狀態(tài)持久化問題

    vuex數(shù)據(jù)狀態(tài)持久化問題

    這篇文章主要介紹了vuex數(shù)據(jù)狀態(tài)持久化問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10

最新評論

乳山市| 葵青区| 大方县| 云南省| 富裕县| 江都市| 子长县| 云林县| 昌邑市| 旬阳县| 北碚区| 依安县| 全椒县| 汉中市| 措美县| 景东| 沙河市| 屏东县| 陈巴尔虎旗| 柳河县| 孙吴县| 同江市| 禹州市| 东平县| 萝北县| 绵阳市| 陆丰市| 临泉县| 嘉荫县| 古交市| 屏边| 定兴县| 台安县| 朝阳县| 科技| 崇阳县| 广平县| 五原县| 介休市| 晋城| 绥江县|