feat: 迁移至 ExtraOptionsPanel

This commit is contained in:
Tinhone 2023-10-11 07:49:43 +08:00
parent 2288a37aec
commit 5f3e401239
6 changed files with 156 additions and 170 deletions

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="custom-font-family-extra-options-entry"> <div class="custom-font-family-extra-options-entry">
<VButton ref="button" @mouseover="loadExtraOptions()" @click="toggleExtraOptionsDisplay()"> <VButton ref="button" @mouseover="loadPanel()" @click="togglePanelDisplay()">
字体设置<VIcon icon="right-arrow" :size="16"></VIcon> 字体设置<VIcon icon="right-arrow" :size="16"></VIcon>
</VButton> </VButton>
</div> </div>
@ -9,12 +9,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { VIcon, VButton } from '@/ui' import { VIcon, VButton } from '@/ui'
import { import { getPanelLoadState, mountPanel, togglePanelDisplay } from './vm'
setTriggerElement,
getExtraOptionsLoadState,
loadExtraOptions,
toggleExtraOptionsDisplay,
} from './vm'
export default defineComponent({ export default defineComponent({
components: { components: {
@ -23,15 +18,13 @@ export default defineComponent({
}, },
methods: { methods: {
async loadExtraOptions() { async loadPanel() {
const isLoaded = await getExtraOptionsLoadState() const isLoaded = await getPanelLoadState()
if (!isLoaded) { if (!isLoaded) {
await loadExtraOptions() await mountPanel()
const triggerButton = this.$refs.button.$el as HTMLElement
setTriggerElement(triggerButton)
} }
}, },
toggleExtraOptionsDisplay, togglePanelDisplay,
}, },
}) })
</script> </script>

View File

@ -1,12 +1,5 @@
<template> <template>
<VPopup <VPopup v-model="popupOpen" class="extra-options-panel" fixed :lazy="false">
ref="popup"
v-model="popupOpen"
class="extra-options-panel"
fixed
:lazy="false"
:trigger-element="triggerElement"
>
<div class="eop-header"> <div class="eop-header">
<div class="eop-h-left"> <div class="eop-h-left">
<VIcon class="eop-h-l-symbol" :icon="initData.header.title.icon" :size="24"></VIcon> <VIcon class="eop-h-l-symbol" :icon="initData.header.title.icon" :size="24"></VIcon>
@ -17,7 +10,8 @@
<VIcon <VIcon
v-for="action in initData.header.actions" v-for="action in initData.header.actions"
:key="action.id" :key="action.id"
:class="`eop-h-r-${action.classNameSuffix}`" :ref="`action${action.id}`"
:class="`eop-h-r-${action.iconClassNameSuffix}`"
:title="action.title" :title="action.title"
:icon="action.icon" :icon="action.icon"
:size="24" :size="24"
@ -35,11 +29,11 @@
<div class="eop-separator"></div> <div class="eop-separator"></div>
<div class="eop-content"> <div class="eop-content">
<div v-for="section in initData.content.sections" :key="section.id" class="eop-c-section"> <div v-for="option in initData.content.options" :key="option.id" class="eop-c-option">
<div class="eop-c-s-title">{{ section.title }}</div> <div class="eop-c-o-title">{{ option.title }}</div>
<div class="eop-c-s-description">{{ section.description }}</div> <div class="eop-c-o-description">{{ option.description }}</div>
<div class="eop-c-s-input" :class="section.inputClassName"> <div class="eop-c-o-input" :class="option.inputClassName">
<slot :name="`eop-c-s-input-slot-${section.id}`"> <slot :name="`eop-c-o-input-slot-${option.id}`">
选项输入入口默认文字使用含 v-slot 指令的 template 元素以替换默认内容 选项输入入口默认文字使用含 v-slot 指令的 template 元素以替换默认内容
</slot> </slot>
</div> </div>
@ -51,46 +45,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { VPopup, VIcon } from '@/ui' import { VPopup, VIcon } from '@/ui'
import { ExtraOptionsPanelInitData } from './extra-options-panel' import { defaultInitData } from './extra-options-panel'
const defaultInitData: ExtraOptionsPanelInitData = {
header: {
title: {
text: '默认标题',
icon: 'mdi-format-font',
},
actions: [
{
id: 0,
title: '默认动作 0',
icon: 'mdi-cog-sync-outline',
classNameSuffix: 'default-action-0',
},
{
id: 1,
title: '默认动作 1',
icon: 'mdi-eye-outline',
classNameSuffix: 'default-action-1',
},
],
},
content: {
sections: [
{
id: 0,
title: '默认选项 0',
description: '默认选项 0 的说明',
inputClassName: 'default-option-0',
},
{
id: 1,
title: '默认选项 1',
description: '默认选项 1 的说明',
inputClassName: 'default-option-1',
},
],
},
}
export default defineComponent({ export default defineComponent({
name: 'ExtraOptionsPanel', name: 'ExtraOptionsPanel',
@ -101,10 +56,6 @@ export default defineComponent({
}, },
props: { props: {
triggerElement: {
type: HTMLElement,
default: null,
},
initData: { initData: {
type: Object, type: Object,
default: defaultInitData, default: defaultInitData,

View File

@ -1,86 +1,73 @@
<template> <template>
<VPopup <ExtraOptionsPanel
ref="popup" ref="extraOptionsPanel"
v-model="popupOpen" class="custom-font-family-extra-options-panel"
class="custom-font-family-extra-options-panel extra-options-panel"
fixed
:lazy="false"
:trigger-element="triggerElement"
:class="{ peek: isPeeking }" :class="{ peek: isPeeking }"
:init-data="initData"
> >
<div class="eop-header"> <template #eop-c-o-input-slot-0>
<div class="eop-h-left"> <TextArea v-model="inputFontFamily" />
<VIcon class="eop-h-l-symbol" icon="mdi-format-font" :size="24"></VIcon> </template>
<div class="eop-h-l-title">字体设置</div> </ExtraOptionsPanel>
</div>
<div class="eop-h-right">
<VIcon
class="eop-h-r-reset"
title="重置面板中的所有选项为默认值"
icon="mdi-cog-sync-outline"
:size="24"
@click="confirmResetOptions()"
></VIcon>
<VIcon
class="eop-h-r-peek"
title="透视"
icon="mdi-eye-outline"
:size="24"
@mouseover="mouseOnPeekIcon = true"
@mouseout="mouseOnPeekIcon = false"
></VIcon>
<VIcon
class="eop-h-r-close"
title="关闭"
icon="mdi-close"
:size="24"
@click="popupOpen = false"
></VIcon>
</div>
</div>
<div class="eop-separator"></div>
<div class="eop-content">
<div class="eop-c-section">
<div class="eop-c-s-title">自定义字体</div>
<div class="eop-c-s-description">输入字体不同字体之间必须以英文逗号分隔</div>
<div class="eop-c-s-input input-font-family">
<TextArea v-model="inputFontFamily" />
</div>
</div>
</div>
</VPopup>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { VPopup, VIcon, TextArea } from '@/ui' import { TextArea } from '@/ui'
import ExtraOptionsPanel from './ExtraOptionsPanel.vue'
import { getComponentSettings } from '@/core/settings' import { getComponentSettings } from '@/core/settings'
import { Toast } from '@/core/toast'
import { delay } from '@/core/utils' import { delay } from '@/core/utils'
import { useScopedConsole } from '@/core/utils/log' import { useScopedConsole } from '@/core/utils/log'
import { fontFamilyDefaultValue } from '../font-family-default-value' import { fontFamilyDefaultValue } from '../font-family-default-value'
import { ExtraOptionsPanelInitData } from './extra-options-panel'
const initData: ExtraOptionsPanelInitData = {
header: {
title: {
text: '自定义字体',
icon: 'mdi-format-font',
},
actions: [
{
id: 0,
title: '重置面板中的所有选项为默认值',
icon: 'mdi-cog-sync-outline',
iconClassNameSuffix: 'reset',
},
{
id: 1,
title: '透视',
icon: 'mdi-eye-outline',
iconClassNameSuffix: 'peek',
},
],
},
content: {
options: [
{
id: 0,
title: '自定义字体',
description: '输入需要设置的字体,不同字体之间必须以英文逗号分隔',
inputClassName: 'input-font-family',
},
],
},
}
const console = useScopedConsole('自定义字体')
export default defineComponent({ export default defineComponent({
components: { components: {
VPopup, ExtraOptionsPanel,
VIcon,
TextArea, TextArea,
}, },
props: {
triggerElement: {
type: HTMLElement,
default: null,
},
},
data() { data() {
return { return {
popupOpen: false,
isPeeking: false, isPeeking: false,
mouseOnPeekIcon: false, isMouseOverPeekIcon: false,
initData,
// inputFontFamily fontFamily // inputFontFamily fontFamily
inputFontFamily: getComponentSettings('customFontFamily').options.fontFamily, inputFontFamily: getComponentSettings('customFontFamily').options.fontFamily,
} }
@ -92,7 +79,7 @@ export default defineComponent({
getComponentSettings('customFontFamily').options.fontFamily = value getComponentSettings('customFontFamily').options.fontFamily = value
}, 500), }, 500),
async mouseOnPeekIcon(value: boolean) { async isMouseOverPeekIcon(value: boolean) {
if (!value) { if (!value) {
this.isPeeking = false this.isPeeking = false
return return
@ -100,13 +87,38 @@ export default defineComponent({
if (value) { if (value) {
await delay(200) await delay(200)
} }
if (this.mouseOnPeekIcon) { if (this.isMouseOverPeekIcon) {
this.isPeeking = true this.isPeeking = true
} }
}, },
}, },
mounted() {
// v-for 使
// ref
// https://cn.vuejs.org/guide/essentials/template-refs.html#refs-inside-v-for
const action0Reset = this.$refs.extraOptionsPanel.$refs.action0[0].$el as HTMLElement
action0Reset.addEventListener('click', this.confirmResetOptions)
const action1Peek = this.$refs.extraOptionsPanel.$refs.action1[0].$el as HTMLElement
action1Peek.addEventListener('mouseover', this.setIsMouseOverPeekIconToTrue)
action1Peek.addEventListener('mouseout', this.setIsMouseOverPeekIconToFalse)
},
methods: { methods: {
toggleDisplay() {
this.$refs.extraOptionsPanel.popupOpen = !this.$refs.extraOptionsPanel.popupOpen
},
setIsMouseOverPeekIconToTrue() {
this.isMouseOverPeekIcon = true
},
setIsMouseOverPeekIconToFalse() {
this.isMouseOverPeekIcon = false
},
confirmResetOptions() { confirmResetOptions() {
if (confirm('确定将面板中的所有选项重置为默认值吗?')) { if (confirm('确定将面板中的所有选项重置为默认值吗?')) {
this.resetOptions() this.resetOptions()
@ -116,20 +128,20 @@ export default defineComponent({
resetOptions() { resetOptions() {
getComponentSettings('customFontFamily').options.fontFamily = fontFamilyDefaultValue getComponentSettings('customFontFamily').options.fontFamily = fontFamilyDefaultValue
this.inputFontFamily = fontFamilyDefaultValue this.inputFontFamily = fontFamilyDefaultValue
const console = useScopedConsole('自定义字体') Toast.success('成功将字体设置面板中的所有选项重置为默认值', '自定义字体', 2000)
console.log('将字体设置面板中的所有选项重置为默认值') console.log('成功将字体设置面板中的所有选项重置为默认值')
}, },
}, },
}) })
</script> </script>
<style lang="scss"> <style lang="scss">
@import './extra-options-panel';
.custom-font-family-extra-options-panel { .custom-font-family-extra-options-panel {
@include extra-options-panel; &.peek {
opacity: 0.1;
}
> .eop-content > .eop-c-section > .eop-c-s-input.input-font-family .be-text-area { > .eop-content > .eop-c-option > .eop-c-o-input.input-font-family > .be-text-area {
min-height: 160px; min-height: 160px;
} }
} }

View File

@ -5,7 +5,7 @@ $prefH: 'eop-h';
$prefHL: 'eop-h-l'; $prefHL: 'eop-h-l';
$prefHR: 'eop-h-r'; $prefHR: 'eop-h-r';
$prefC: 'eop-c'; $prefC: 'eop-c';
$prefCS: 'eop-c-s'; $prefCO: 'eop-c-o';
$panelPadding: 22px; $panelPadding: 22px;
@ -28,10 +28,6 @@ $panelPadding: 22px;
transform: translateX(-50%) translateY(-50%) scale(1); transform: translateX(-50%) translateY(-50%) scale(1);
} }
&.peek {
opacity: 0.1;
}
> .#{$pref}-header { > .#{$pref}-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -81,25 +77,25 @@ $panelPadding: 22px;
flex-grow: 1; flex-grow: 1;
flex-shrink: 1; flex-shrink: 1;
> .#{$prefC}-section { > .#{$prefC}-option {
margin: 18px 0; margin: 18px 0;
&:nth-child(1):nth-last-child(1) { &:nth-child(1):nth-last-child(1) {
margin-bottom: 12px; margin-bottom: 12px;
} }
> .#{$prefCS}-title { > .#{$prefCO}-title {
margin-bottom: 2px; margin-bottom: 2px;
font-size: 14px; font-size: 14px;
} }
> .#{$prefCS}-description { > .#{$prefCO}-description {
margin-bottom: 8px; margin-bottom: 8px;
opacity: 0.6; opacity: 0.6;
font-size: 12px; font-size: 12px;
} }
> .#{$prefCS}-input { > .#{$prefCO}-input {
@include h-center(); @include h-center();
flex-wrap: wrap; flex-wrap: wrap;
} }

View File

@ -7,19 +7,19 @@ export interface ExtraOptionsPanelInitData {
icon: string icon: string
} }
actions: { actions: {
/** 动作按钮序号,从 0 开始增长,不可重复 */ /** 动作按钮序号,从 0 开始增长,重复将会导致渲染异常 */
id: number id: number
/** 动作按钮标题 */ /** 动作按钮标题 */
title: string title: string
/** 动作按钮图标 */ /** 动作按钮图标 */
icon: string icon: string
/** 动作按钮类名的后缀,直接写一个贴切的名字就好了 */ /** 动作按钮类名的后缀,直接写一个贴切的名字就好了 */
classNameSuffix: string iconClassNameSuffix: string
}[] }[]
} }
content: { content: {
sections: { options: {
/** 选项序号,从 0 开始增长,不可重复 */ /** 选项序号,从 0 开始增长,重复将会导致渲染异常。另外会在类似 eop-c-s-input-slot-0 的具名插槽用到 */
id: number id: number
/** 选项标题 */ /** 选项标题 */
title: string title: string
@ -30,3 +30,42 @@ export interface ExtraOptionsPanelInitData {
}[] }[]
} }
} }
export const defaultInitData: ExtraOptionsPanelInitData = {
header: {
title: {
text: '默认标题',
icon: 'mdi-format-font',
},
actions: [
{
id: 0,
title: '默认动作 0',
icon: 'mdi-cog-sync-outline',
iconClassNameSuffix: 'default-action-0',
},
{
id: 1,
title: '默认动作 1',
icon: 'mdi-eye-outline',
iconClassNameSuffix: 'default-action-1',
},
],
},
content: {
options: [
{
id: 0,
title: '默认选项 0',
description: '默认选项 0 的说明',
inputClassName: 'default-option-0',
},
{
id: 1,
title: '默认选项 1',
description: '默认选项 1 的说明',
inputClassName: 'default-option-1',
},
],
},
}

View File

@ -1,24 +1,19 @@
import { mountVueComponent } from '@/core/utils' import { mountVueComponent } from '@/core/utils'
let extraOptionsVm: Vue & { let panelVm: Vue & {
popupOpen: boolean toggleDisplay: () => void
triggerElement: HTMLElement
} }
export const setTriggerElement = (element: HTMLElement) => { export const getPanelLoadState = async () => {
extraOptionsVm.triggerElement = element return Boolean(panelVm)
} }
export const getExtraOptionsLoadState = async () => { export const mountPanel = async () => {
return Boolean(extraOptionsVm) const panel = await import('./Panel1.vue').then(m => m.default)
panelVm = mountVueComponent(panel)
document.body.insertAdjacentElement('beforeend', panelVm.$el)
} }
export const loadExtraOptions = async () => { export const togglePanelDisplay = async () => {
const extraOptions = await import('./Panel1.vue').then(m => m.default) panelVm.toggleDisplay()
extraOptionsVm = mountVueComponent(extraOptions)
document.body.insertAdjacentElement('beforeend', extraOptionsVm.$el)
}
export const toggleExtraOptionsDisplay = async () => {
extraOptionsVm.popupOpen = !extraOptionsVm.popupOpen
} }