Merge pull request #99 from JeremyYu-cn/feat-upgrade-vue3

Feat convert wrap components to composition API
This commit is contained in:
Jeremy Yu 2024-03-21 19:12:10 +00:00 committed by GitHub
commit 4d4026492e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 981 additions and 822 deletions

View File

@ -73,6 +73,7 @@ export const getFontSub = (params: TGetFontSubParam, extra: TGetFontSubExtra = {
type TGetImageListParams = { type TGetImageListParams = {
page?: number page?: number
pageSize?: number
cate?: number cate?: number
} }

View File

@ -14,6 +14,7 @@ export type TStyleIconData = {
tip: string tip: string
value: string[] value: string[]
select: boolean select: boolean
extraIcon?: boolean,
} }
export const styleIconList1 = [ export const styleIconList1 = [

View File

@ -13,7 +13,8 @@ import wImageSetting from '@/components/modules/widgets/wImage/wImageSetting'
// import wText from '@/components/modules/widgets/wText/wText.vue' // import wText from '@/components/modules/widgets/wText/wText.vue'
import { wTextSetting } from '@/components/modules/widgets/wText/wTextSetting' import { wTextSetting } from '@/components/modules/widgets/wText/wTextSetting'
import wImage from '@/components/modules/widgets/wImage/wImage.vue' import wImage from '@/components/modules/widgets/wImage/wImage.vue'
import wSvg from '@/components/modules/widgets/wSvg/wSvg.vue' // import wSvg from '@/components/modules/widgets/wSvg/wSvg.vue'
import { wSvgSetting } from '@/components/modules/widgets/wSvg/wSvgSetting'
export default async function(type: string, item: TCommonItemData, data: Record<string, any>) { export default async function(type: string, item: TCommonItemData, data: Record<string, any>) {
let setting = data let setting = data
@ -36,7 +37,7 @@ export default async function(type: string, item: TCommonItemData, data: Record<
setting.mask = item.value.url setting.mask = item.value.url
} }
if (type === 'svg') { if (type === 'svg') {
setting = JSON.parse(JSON.stringify(wSvg.setting)) setting = JSON.parse(JSON.stringify(wSvgSetting))
const img = await setImageData(item.value) const img = await setImageData(item.value)
setting.width = img.width setting.width = img.width
setting.height = img.height // parseInt(100 / item.value.ratio, 10) setting.height = img.height // parseInt(100 / item.value.ratio, 10)

View File

@ -7,7 +7,7 @@
--> -->
<template> <template>
<div class="wrap"> <div class="wrap">
<search-header v-model="searchKeyword" type="none" @change="searchChange" /> <search-header v-model="state.searchKeyword" type="none" @change="searchChange" />
<div style="height: 0.5rem" /> <div style="height: 0.5rem" />
<!-- <div class="types"> <!-- <div class="types">
<div v-for="(t, ti) in types" :key="ti + 't'" :style="{ backgroundColor: colors[ti] }" :class="['types__item', { 'types--select': currentType === t.id }]" @click="selectType(t)"></div> <div v-for="(t, ti) in types" :key="ti + 't'" :style="{ backgroundColor: colors[ti] }" :class="['types__item', { 'types--select': currentType === t.id }]" @click="selectType(t)"></div>
@ -15,47 +15,50 @@
<!-- <div class="tags"> <!-- <div class="tags">
<el-check-tag v-for="(t2, t2i) in sub" :key="t2i + 't2'" :checked="t2.id === currentCheck" class="tags__item" @click="tagsChange(t2.id)">{{ t2.name }}</el-check-tag> <el-check-tag v-for="(t2, t2i) in sub" :key="t2i + 't2'" :checked="t2.id === currentCheck" class="tags__item" @click="tagsChange(t2.id)">{{ t2.name }}</el-check-tag>
</div> --> </div> -->
<classHeader v-show="!currentCategory" :types="types" @select="selectTypes"> <classHeader v-show="!state.currentCategory" :types="state.types" @select="selectTypes">
<template v-slot="{ index }"> <template v-slot="{ index }">
<div class="list-wrap"> <div class="list-wrap">
<div v-for="(item, i) in showList[index]" :key="i + 'sl'" draggable="false" @mousedown="dragStart($event, item)" @mousemove="mousemove" @mouseup="mouseup" @click.stop="selectItem(item)" @dragstart="dragStart($event, item)"> <div v-for="(item, i) in state.showList[index]" :key="i + 'sl'" draggable="false" @mousedown="dragStart($event, item)" @mousemove="mousemove" @mouseup="mouseup" @click.stop="selectItem(item)" @dragstart="dragStart($event, item)">
<el-image class="list__img-thumb" :src="item.thumb" fit="contain" lazy loading="lazy" /> <el-image class="list__img-thumb" :src="item.thumb" fit="contain" lazy loading="lazy" />
</div> </div>
</div> </div>
</template> </template>
</classHeader> </classHeader>
<ul v-if="currentCategory" v-infinite-scroll="load" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto"> <ul v-if="state.currentCategory" v-infinite-scroll="load" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto">
<classHeader :is-back="true" @back="back">{{ currentCategory.name }}</classHeader> <classHeader :is-back="true" @back="back">{{ state.currentCategory.name }}</classHeader>
<el-space fill wrap :fillRatio="30" direction="horizontal" class="list"> <el-space fill wrap :fillRatio="30" direction="horizontal" class="list">
<div v-for="(item, i) in list" :key="i + 'i'" class="list__item" draggable="false" @mousedown="dragStart($event, item)" @mousemove="mousemove" @mouseup="mouseup" @click.stop="selectItem(item)" @dragstart="dragStart($event, item)"> <div v-for="(item, i) in state.list" :key="i + 'i'" class="list__item" draggable="false" @mousedown="dragStart($event, item)" @mousemove="mousemove" @mouseup="mouseup" @click.stop="selectItem(item)" @dragstart="dragStart($event, item)">
<el-image class="list__img" :src="item.thumb" fit="contain" lazy loading="lazy" /> <el-image class="list__img" :src="item.thumb" fit="contain" lazy loading="lazy" />
</div> </div>
</el-space> </el-space>
<div v-show="loading" class="loading"><i class="el-icon-loading" /> 拼命加载中</div> <div v-show="state.loading" class="loading"><i class="el-icon-loading" /> 拼命加载中</div>
<div v-show="loadDone" :style="list.length <= 0 ? 'padding-top: 4rem' : ''" class="loading">全部加载完毕</div> <div v-show="state.loadDone" :style="state.list.length <= 0 ? 'padding-top: 4rem' : ''" class="loading">全部加载完毕</div>
</ul> </ul>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, reactive, toRefs, onMounted, watch } from 'vue' import { reactive, onMounted } from 'vue'
import api from '@/api' import api from '@/api'
// import wImage from '../../widgets/wImage/wImage.vue' // import wImage from '../../widgets/wImage/wImage.vue'
import wImageSetting from '../../widgets/wImage/wImageSetting' import wImageSetting from '../../widgets/wImage/wImageSetting'
import wSvg from '../../widgets/wSvg/wSvg.vue' // import wSvg from '../../widgets/wSvg/wSvg.vue'
import { mapActions, mapGetters } from 'vuex' import { wSvgSetting } from '../../widgets/wSvg/wSvgSetting'
import { useStore } from 'vuex'
import setImageData from '@/common/methods/DesignFeatures/setImage' import setImageData from '@/common/methods/DesignFeatures/setImage'
import DragHelper from '@/common/hooks/dragHelper' import DragHelper from '@/common/hooks/dragHelper'
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
type TProps = {
active?: boolean
}
let isDrag = false let isDrag = false
let startPoint = { x: 99999, y: 99999 } let startPoint = { x: 99999, y: 99999 }
const dragHelper = new DragHelper() const dragHelper = new DragHelper()
export default defineComponent({ const prpos = defineProps<TProps>()
components: {},
props: ['active'],
setup(props) {
const colors = ['#f8704b', '#5b89ff', '#2cc4cc', '#a8ba73', '#f8704b'] const colors = ['#f8704b', '#5b89ff', '#2cc4cc', '#a8ba73', '#f8704b']
const state: any = reactive({ const state: any = reactive({
loading: false, loading: false,
@ -71,6 +74,10 @@ export default defineComponent({
searchKeyword: '', searchKeyword: '',
}) })
const pageOptions = { page: 0, pageSize: 20 } const pageOptions = { page: 0, pageSize: 20 }
const store = useStore()
const {
dPage
} = useSetupMapGetters(['dPage'])
onMounted(async () => { onMounted(async () => {
if (state.types.length <= 0) { if (state.types.length <= 0) {
@ -140,32 +147,30 @@ export default defineComponent({
state.currentCategory = null state.currentCategory = null
} }
return { defineExpose({
...toRefs(state),
load, load,
searchChange, searchChange,
selectTypes, selectTypes,
back, back,
mouseup, mouseup,
mousemove, mousemove,
} })
},
computed: { // ...mapGetters(['dPage'])
...mapGetters(['dPage']),
}, // ...mapActions(['addWidget'])
methods: {
...mapActions(['addWidget']), async function selectItem(item: any) {
async selectItem(item: any) {
if (isDrag) { if (isDrag) {
return return
} }
this.$store.commit('setShowMoveable', false) // store.commit('setShowMoveable', false) //
let setting = item.type === 'svg' ? JSON.parse(JSON.stringify(wSvg.setting)) : JSON.parse(JSON.stringify(wImageSetting)) let setting = item.type === 'svg' ? JSON.parse(JSON.stringify(wSvgSetting)) : JSON.parse(JSON.stringify(wImageSetting))
const img: any = await setImageData(item) const img: any = await setImageData(item)
setting.width = img.width setting.width = img.width
setting.height = img.height // parseInt(100 / item.value.ratio, 10) setting.height = img.height // parseInt(100 / item.value.ratio, 10)
const { width: pW, height: pH } = this.dPage const { width: pW, height: pH } = dPage.value
setting.left = pW / 2 - img.width / 2 setting.left = pW / 2 - img.width / 2
setting.top = pH / 2 - img.height / 2 setting.top = pH / 2 - img.height / 2
setting.imgUrl = item.url setting.imgUrl = item.url
@ -181,17 +186,16 @@ export default defineComponent({
if (item.type === 'mask') { if (item.type === 'mask') {
setting.mask = item.url setting.mask = item.url
} }
this.addWidget(setting) store.dispatch("addWidget", setting)
}, // addWidget(setting)
async dragStart(e: any, item: any) { }
async function dragStart(e: any, item: any) {
startPoint = { x: e.x, y: e.y } startPoint = { x: e.x, y: e.y }
const { width, height, thumb, url } = item const { width, height, thumb, url } = item
const img = await setImageData({ width, height, url: thumb || url }) const img = await setImageData({ width, height, url: thumb || url })
dragHelper.start(e, img.canvasWidth) dragHelper.start(e, img.canvasWidth)
this.$store.commit('selectItem', { data: { value: item }, type: item.type }) store.commit('selectItem', { data: { value: item }, type: item.type })
}, }
},
})
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -9,22 +9,22 @@
<div class="wrap"> <div class="wrap">
<search-header type="none" @change="searchChange" /> <search-header type="none" @change="searchChange" />
<div style="height: 0.5rem" /> <div style="height: 0.5rem" />
<classHeader v-show="!currentCategory" :types="types" @select="selectTypes"> <classHeader v-show="!state.currentCategory" :types="state.types" @select="selectTypes">
<template v-slot="{ index }"> <template v-slot="{ index }">
<photo-list :isShort="true" :listData="showList[index]" @load="getDataList" @drag="dragStart($event, showList[index])" @select="selectImg($event, showList[index])" /> <photo-list :isShort="true" :listData="state.showList[index]" @load="getDataList" @drag="dragStart($event, state.showList[index])" @select="selectImg($event, state.showList[index])" />
</template> </template>
</classHeader> </classHeader>
<div v-if="currentCategory"> <div v-if="state.currentCategory">
<classHeader :is-back="true" @back="back">{{ currentCategory.name }}</classHeader> <classHeader :is-back="true" @back="back">{{ state.currentCategory.name }}</classHeader>
<br /><br /><br /> <br /><br /><br />
<div style="margin: 0 1rem; height: 100vh"> <div style="margin: 0 1rem; height: 100vh">
<photo-list :isDone="loadDone" :listData="recommendImgList" @load="getDataList" @drag="dragStart" @select="selectImg" /> <photo-list :isDone="state.loadDone" :listData="state.recommendImgList" @load="getDataList" @drag="dragStart" @select="selectImg" />
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script lang="ts" setup>
// //
const NAME = 'img-list-wrap' const NAME = 'img-list-wrap'
import { toRefs, reactive, computed, onMounted } from 'vue' import { toRefs, reactive, computed, onMounted } from 'vue'
@ -33,14 +33,25 @@ import wImageSetting from '../../widgets/wImage/wImageSetting'
import api from '@/api' import api from '@/api'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import setImageData from '@/common/methods/DesignFeatures/setImage' import setImageData from '@/common/methods/DesignFeatures/setImage'
import { TGetImageListResult } from '@/api/material';
type TProps = {
active?: boolean
}
type TState = {
recommendImgList: TGetImageListResult[],
loadDone: boolean,
page: 0,
currentCategory: null | Record<string, any>,
types: [],
showList: TGetImageListResult[][],
}
const props = defineProps<TProps>()
export default {
name: NAME,
components: {},
props: ['active'],
setup() {
const store = useStore() const store = useStore()
const state = reactive({ const state = reactive<TState>({
recommendImgList: [], recommendImgList: [],
loadDone: false, loadDone: false,
page: 0, page: 0,
@ -62,7 +73,7 @@ export default {
} }
}) })
const selectImg = async (index, list) => { const selectImg = async (index: number, list: TGetImageListResult[]) => {
const item = list ? list[index] : state.recommendImgList[index] const item = list ? list[index] : state.recommendImgList[index]
store.commit('setShowMoveable', false) // store.commit('setShowMoveable', false) //
let setting = JSON.parse(JSON.stringify(wImageSetting)) let setting = JSON.parse(JSON.stringify(wImageSetting))
@ -70,7 +81,7 @@ export default {
setting.width = img.width setting.width = img.width
setting.height = img.height // parseInt(100 / item.value.ratio, 10) setting.height = img.height // parseInt(100 / item.value.ratio, 10)
setting.imgUrl = item.url setting.imgUrl = item.url
const { width: pW, height: pH } = dPage const { width: pW, height: pH } = dPage.value
setting.left = pW / 2 - img.width / 2 setting.left = pW / 2 - img.width / 2
setting.top = pH / 2 - img.height / 2 setting.top = pH / 2 - img.height / 2
store.dispatch('addWidget', setting) store.dispatch('addWidget', setting)
@ -82,6 +93,7 @@ export default {
} }
loading = true loading = true
state.page += 1 state.page += 1
if (!state.currentCategory) return
let { list = [], total } = await api.material.getImagesList({ cate: state.currentCategory.id, page: state.page, pageSize: 30 }) let { list = [], total } = await api.material.getImagesList({ cate: state.currentCategory.id, page: state.page, pageSize: 30 })
list.length <= 0 ? (state.loadDone = true) : (state.recommendImgList = state.recommendImgList.concat(list)) list.length <= 0 ? (state.loadDone = true) : (state.recommendImgList = state.recommendImgList.concat(list))
setTimeout(() => { setTimeout(() => {
@ -89,16 +101,16 @@ export default {
}, 100) }, 100)
} }
const dragStart = (index, list) => { const dragStart = (index: number, list?: TGetImageListResult[]) => {
const item = list ? list[index] : state.recommendImgList[index] const item = list ? list[index] : state.recommendImgList[index]
store.commit('selectItem', { data: { value: item }, type: 'image' }) store.commit('selectItem', { data: { value: item }, type: 'image' })
} }
const searchChange = (e) => { const searchChange = (e: Record<string, any>) => {
console.log(e) console.log(e)
} }
const selectTypes = (item) => { const selectTypes = (item: Record<string, any>) => {
state.currentCategory = item state.currentCategory = item
getDataList() getDataList()
} }
@ -109,17 +121,14 @@ export default {
state.recommendImgList = [] state.recommendImgList = []
} }
return { defineExpose({
...toRefs(state),
selectImg, selectImg,
getDataList, getDataList,
dragStart, dragStart,
searchChange, searchChange,
selectTypes, selectTypes,
back, back,
} })
},
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -42,7 +42,8 @@
import api from '@/api' import api from '@/api'
import { toRefs, reactive, watch, onMounted, nextTick } from 'vue' import { toRefs, reactive, watch, onMounted, nextTick } from 'vue'
import { ElRadioGroup, ElRadioButton } from 'element-plus' import { ElRadioGroup, ElRadioButton } from 'element-plus'
import wSvg from '@/components/modules/widgets/wSvg/wSvg.vue' // import wSvg from '@/components/modules/widgets/wSvg/wSvg.vue'
import {wSvgSetting} from '@/components/modules/widgets/wSvg/wSvgSetting'
import { TGetListResult } from '@/api/material'; import { TGetListResult } from '@/api/material';
type TProps = { type TProps = {
@ -75,7 +76,7 @@ const state = reactive<TState>({
const select = (value: string = '') => { const select = (value: string = '') => {
state.visiable = false state.visiable = false
const setting = JSON.parse(JSON.stringify(wSvg.setting)) const setting = JSON.parse(JSON.stringify(wSvgSetting))
setting.svgUrl = value setting.svgUrl = value
emit('change', setting) emit('change', setting)
} }

View File

@ -28,7 +28,7 @@ export type TIconItemSelectData = {
extraIcon?: boolean, extraIcon?: boolean,
tip?: string tip?: string
icon?: string icon?: string
value?: string | number value?: string | number | number[] | string[]
} }
type TProps = { type TProps = {

View File

@ -4,10 +4,10 @@
<template> <template>
<div <div
:id="params.uuid" :id="params.uuid"
ref="widget" ref="widgetRef"
class="w-svg" class="w-svg"
:style="{ :style="{
position, position: state.position,
left: params.left - parent.left + 'px', left: params.left - parent.left + 'px',
top: params.top - parent.top + 'px', top: params.top - parent.top + 'px',
width: params.width + 'px', width: params.width + 'px',
@ -17,40 +17,34 @@
></div> ></div>
</template> </template>
<script> <script lang="ts" setup>
// svg // svg
const NAME = 'w-svg' // const NAME = 'w-svg'
import { mapGetters, mapActions, useStore } from 'vuex'
import { TWSvgSetting } from './wSvgSetting'
import { CSSProperties, computed, nextTick, onBeforeMount, onMounted, onUpdated, reactive, ref, watch } from 'vue';
import { useSetupMapGetters } from '@/common/hooks/mapGetters';
import { mapGetters, mapActions } from 'vuex' type TProps = {
params: TWSvgSetting
parent: {
left: number
top: number
}
}
export default { type TState = {
name: NAME, position: CSSProperties['position'], // 'absolute'relative
setting: { editBoxStyle: CSSProperties,
name: '矢量图形', editBoxs: Record<string, any>,
type: NAME, editingKey: string,
uuid: -1, cropWidgetXY: Record<string, any>, //
width: 100, attrRecord: Record<string, any>, //
height: 100, svgImg: Record<string, any> | null
colors: [], }
left: 0,
top: 0, const props = defineProps<TProps>()
// zoom: 1.5, const state = reactive<TState>({
transform: '',
radius: 0,
opacity: 1,
parent: '-1',
svgUrl: '',
setting: [],
record: {
width: 0,
height: 0,
minWidth: 10,
minHeight: 10,
},
},
props: ['params', 'parent'],
data() {
return {
position: 'absolute', // 'absolute'relative position: 'absolute', // 'absolute'relative
editBoxStyle: { editBoxStyle: {
transformOrigin: 'center', transformOrigin: 'center',
@ -59,66 +53,90 @@ export default {
editingKey: '', editingKey: '',
cropWidgetXY: {}, // cropWidgetXY: {}, //
attrRecord: {}, // attrRecord: {}, //
} svgImg: null
},
computed: {
...mapGetters(['dActiveElement', 'dZoom', 'dMouseXY']),
tZoom() {
return this.params.zoom
},
cropEdit() {
return this.params.cropEdit
},
imgChange() {
return this.params.imgUrl
},
},
watch: {
params: {
async handler(nval) {
this.attrsChange()
},
immediate: true,
deep: true,
},
async tZoom() {
await this.$nextTick()
this.updateRecord()
},
imgChange() {
// TODO
this.svgImg.attr({
'xlink:href': this.params.imgUrl,
}) })
const store = useStore()
// ...mapGetters(['dActiveElement', 'dZoom', 'dMouseXY']),
const {
dActiveElement, dZoom, dMouseXY
} = useSetupMapGetters(['dActiveElement', 'dZoom', 'dMouseXY'])
const widgetRef = ref<HTMLElement | null>(null)
let svgElements: Record<string, any>[] | null = null
let viewBox = { width: 0, height: 0 }
const tZoom = computed(() => {
return props.params.zoom
})
const cropEdit = computed(() => {
return props.params.cropEdit
})
const imgChange = computed(() => {
return props.params.imgUrl
})
watch(
() => props.params,
() => {
attrsChange()
}, },
cropEdit(val) { { immediate: true, deep: true }
// TODO )
if (val) {
document.getElementById(this.params.uuid).addEventListener('mousedown', this.touchstart, false) watch(
} else { () => tZoom.value,
document.getElementById(this.params.uuid).removeEventListener('mousedown', this.touchstart, false) async () => {
await nextTick()
updateRecord()
} }
}, )
},
updated() { watch(
this.updateRecord() () => imgChange.value,
this.$store.commit('updateRect') () => {
}, if (!state.svgImg) return
async mounted() { state.svgImg.attr({
await this.$nextTick() 'xlink:href': props.params.imgUrl,
await this.loadSvg() })
this.updateRecord() }
// document.getElementById(this.params.uuid).addEventListener('mousedown', this.touchstart, false) )
document.addEventListener('mouseup', this.touchend, false)
this.params.transform && (this.$refs.widget.style.transform = this.params.transform) watch(
this.params.rotate && (this.$refs.widget.style.transform += `rotate(${this.params.rotate})`) () => cropEdit.value,
}, (val) => {
beforeUnmount() { const el = document.getElementById(props.params.uuid)
document.removeEventListener('mouseup', this.touchend, false) if (val) {
}, el?.addEventListener('mousedown', touchstart, false)
methods: { } else {
...mapActions(['updateWidgetData']), el?.removeEventListener('mousedown', touchstart, false)
touchstart(e) { }
}
)
onUpdated(() => {
updateRecord()
store.commit('updateRect')
})
onMounted(async () => {
await nextTick()
await loadSvg()
updateRecord()
document.getElementById(props.params.uuid)?.addEventListener('mousedown', touchstart, false)
document.addEventListener('mouseup', touchend, false)
if (!widgetRef.value) return
props.params.transform && (widgetRef.value.style.transform = props.params.transform)
props.params.rotate && (widgetRef.value.style.transform += `rotate(${props.params.rotate})`)
})
onBeforeMount(() => {
// document.removeEventListener('mouseup', touchend, false)
})
// ...mapActions(['updateWidgetData'])
function touchstart(e: MouseEvent) {
// TODO move start // TODO move start
// const imgKey = e.target.getAttribute('img-key') // const imgKey = e.target.getAttribute('img-key')
// this.editingKey = imgKey // this.editingKey = imgKey
@ -126,47 +144,52 @@ export default {
// transformOrigin: 'center', // transformOrigin: 'center',
// } // }
// const editBox = this.$refs[this.params.uuid + '_ebox_' + imgKey] // const editBox = this.$refs[this.params.uuid + '_ebox_' + imgKey]
const editBox = this.$refs[this.params.uuid + '_ebox'] // const editBox = this.$refs[this.params.uuid + '_ebox']
this.cropWidgetXY = { const editBox = document.getElementById(props.params.uuid + '_ebox')
if (editBox) {
state.cropWidgetXY = {
x: Number(editBox.style.left.replace('px', '')) || 0, x: Number(editBox.style.left.replace('px', '')) || 0,
y: Number(editBox.style.top.replace('px', '')) || 0, y: Number(editBox.style.top.replace('px', '')) || 0,
} }
}
// //
document.addEventListener('mousemove', this.handlemousemove, true) document.addEventListener('mousemove', handlemousemove, true)
}, }
touchend() {
function touchend() {
// //
document.removeEventListener('mousemove', this.handlemousemove, true) document.removeEventListener('mousemove', handlemousemove, true)
// document.removeEventListener('mouseup', () => {}, true) // document.removeEventListener('mouseup', () => {}, true)
}, }
handlemousemove(e) {
function handlemousemove(e: MouseEvent) {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
const { left, top } = this.move(e) const { left, top } = move(e)
// TODO // TODO
this.editBoxStyle.left = left + 'px' state.editBoxStyle.left = left + 'px'
this.editBoxStyle.top = top + 'px' state.editBoxStyle.top = top + 'px'
// this.editBoxs[this.editingKey].left = left + 'px' // this.editBoxs[this.editingKey].left = left + 'px'
// this.editBoxs[this.editingKey].top = top + 'px' // this.editBoxs[this.editingKey].top = top + 'px'
const { width, height } = this.params const { width, height } = props.params
const { width: vWidth, height: vHeight } = this.viewBox const { width: vWidth, height: vHeight } = viewBox
const params = { const params = {
x: left / (width / vWidth) / this.params.zoom, x: left / (width / vWidth) / (props.params.zoom || 0),
y: top / (height / vHeight) / this.params.zoom, y: top / (height / vHeight) / (props.params.zoom || 0),
} }
// this.svgImg.attr(params) // this.svgImg.attr(params)
this.changeFinish('x', params.x) changeFinish('x', params.x)
this.changeFinish('y', params.y) changeFinish('y', params.y)
// console.log('-----', left / (width / vWidth) / this.params.zoom) // console.log('-----', left / (width / vWidth) / this.params.zoom)
}, }
loadSvg() {
function loadSvg() {
// console.log(this.params) // console.log(this.params)
const _this = this const Snap = (window as any).Snap
const Snap = window.Snap return new Promise<void>((resolve) => {
return new Promise((resolve) => {
Snap.load( Snap.load(
this.params.svgUrl, props.params.svgUrl,
function (svg) { function (svg: Record<string, any>) {
let svg2 = Snap(svg.node) let svg2 = Snap(svg.node)
// let item = svg2.select('circle') // let item = svg2.select('circle')
// item.attr({ // item.attr({
@ -179,18 +202,18 @@ export default {
svg2.node.removeAttribute('height') svg2.node.removeAttribute('height')
svg2.node.setAttribute('style', 'height: inherit;width: inherit;') svg2.node.setAttribute('style', 'height: inherit;width: inherit;')
// svg2.node.setAttribute('height', 'inherit') // svg2.node.setAttribute('height', 'inherit')
_this.svgElements = [] svgElements = []
const colorsObj = _this.color2obj() const colorsObj = color2obj()
deepElement(items) deepElement(items)
function deepElement(els) { function deepElement(els: Record<string, any>) {
// NodeList // NodeList
if (els.item) { if (els.item) {
els.forEach((element) => { els.forEach((element: Record<string, any>) => {
elementFactory(element) elementFactory(element)
if (element.childNodes.length > 0) { if (element.childNodes.length > 0) {
element.childNodes.forEach((element) => { element.childNodes.forEach((element: Record<string, any>) => {
deepElement(element) deepElement(element)
}) })
} }
@ -200,19 +223,19 @@ export default {
} }
} }
// : // :
function elementFactory(element) { function elementFactory(element: Record<string, any>) {
const attrsColor = {} const attrsColor: Record<string, any> = {}
try { try {
element.attributes.forEach((attr) => { element.attributes.forEach((attr: Record<string, any>) => {
if (colorsObj[attr.value]) { if (colorsObj[attr.value]) {
// console.log(attr.name, colorsObj[attr.value]) // console.log(attr.name, colorsObj[attr.value])
attr.value = colorsObj[attr.value] attr.value = colorsObj[attr.value]
attrsColor[attr.name] = _this.params.colors.findIndex((x) => x == attr.value) attrsColor[attr.name] = props.params.colors.findIndex((x) => x == attr.value)
} }
}) })
} catch (e) {} } catch (e) {}
if (JSON.stringify(attrsColor) !== '{}') { if (JSON.stringify(attrsColor) !== '{}' && svgElements) {
_this.svgElements.push({ svgElements.push({
item: element, item: element,
attrsColor, attrsColor,
}) })
@ -229,88 +252,101 @@ export default {
// transform: '', // transform: '',
// 'xlink:href': _this.params.imgUrl || '', // 'xlink:href': _this.params.imgUrl || '',
// }) // })
const el = this || _this.$refs.widget if (widgetRef.value) {
// svg.node.classList.add('svg__box') // svg.node.classList.add('svg__box')
el.appendChild(svg.node) widgetRef.value.appendChild(svg.node)
}
resolve() resolve()
}, },
document.getElementById(this.params.uuid), document.getElementById(props.params.uuid),
) )
}) })
}, }
color2obj() {
const obj = {} function color2obj() {
for (let i = 0; i < this.params.colors.length; i++) { const obj: Record<string, any> = {}
obj[`{{colors[${i}]}}`] = this.params.colors[i] for (let i = 0; i < props.params.colors.length; i++) {
obj[`{{colors[${i}]}}`] = props.params.colors[i]
} }
return obj return obj
},
updateRecord() {
if (this.dActiveElement.uuid === this.params.uuid) {
let record = this.dActiveElement.record
record.width = this.$refs.widget.offsetWidth
record.height = this.$refs.widget.offsetHeight
} }
this.updateZoom()
}, function updateRecord() {
updateZoom() { if (dActiveElement.value.uuid === props.params.uuid) {
let record = dActiveElement.value.record
if (widgetRef.value) {
record.width = widgetRef.value.offsetWidth
record.height = widgetRef.value.offsetHeight
}
}
updateZoom()
}
function updateZoom() {
// TODO // TODO
this.editBoxStyle.transform = `scale(${this.params.zoom})` state.editBoxStyle.transform = `scale(${props.params.zoom})`
// this.editingKey && (this.editBoxs[this.editingKey].transform = `scale(${this.params.zoom})`) // this.editingKey && (this.editBoxs[this.editingKey].transform = `scale(${this.params.zoom})`)
if (this.svgImg) { if (state.svgImg) {
const { x, y } = this.params const { x = 0, y = 0 } = props.params
this.svgImg.attr({ state.svgImg.attr({
x: x || 0, x: x ?? 0,
y: y || 0, y: y ?? 0,
style: `transform-origin: center;transform: scale(${this.params.zoom})`, style: `transform-origin: center;transform: scale(${props.params.zoom})`,
}) })
// editBox // editBox
const { width, height } = this.params const { width, height } = props.params
const { width: vWidth, height: vHeight } = this.viewBox const { width: vWidth, height: vHeight } = viewBox
const params = { const params = {
left: x * (width / vWidth) * this.params.zoom, left: x * (width / vWidth) * (props.params.zoom || 0),
top: y * (height / vHeight) * this.params.zoom, top: y * (height / vHeight) * (props.params.zoom || 0),
} }
// TODO // TODO
this.editBoxStyle.left = params.left + 'px' state.editBoxStyle.left = params.left + 'px'
this.editBoxStyle.top = params.top + 'px' state.editBoxStyle.top = params.top + 'px'
// if (this.editingKey) { // if (this.editingKey) {
// this.editBoxs[this.editingKey].left = params.left + 'px' // this.editBoxs[this.editingKey].left = params.left + 'px'
// this.editBoxs[this.editingKey].top = params.top + 'px' // this.editBoxs[this.editingKey].top = params.top + 'px'
// } // }
} }
}, }
changeFinish(key, value) {
this.updateWidgetData({ function changeFinish(key: string, value: number) {
uuid: this.params.uuid, store.dispatch("updateWidgetData", {
uuid: props.params.uuid,
key: key, key: key,
value: value, value: value,
pushHistory: true, pushHistory: true,
}) })
}, // this.updateWidgetData({
move(payload) { // uuid: this.params.uuid,
// key: key,
// value: value,
// pushHistory: true,
// })
}
function move(payload: Record<string, any>) {
// const widgetXY = { x: this.cropWidgetXY.x / this.dZoom, y: this.cropWidgetXY.y / this.dZoom } // const widgetXY = { x: this.cropWidgetXY.x / this.dZoom, y: this.cropWidgetXY.y / this.dZoom }
const widgetXY = { x: this.cropWidgetXY.x, y: this.cropWidgetXY.y } const widgetXY = { x: state.cropWidgetXY.x, y: state.cropWidgetXY.y }
const dx = Number(payload.pageX) - this.dMouseXY.x const dx = Number(payload.pageX) - dMouseXY.value.x
const dy = Number(payload.pageY) - this.dMouseXY.y const dy = Number(payload.pageY) - dMouseXY.value.y
let left = Number(widgetXY.x) + Math.floor((dx * 100) / this.dZoom) let left = Number(widgetXY.x) + Math.floor((dx * 100) / dZoom.value)
let top = Number(widgetXY.y) + Math.floor((dy * 100) / this.dZoom) let top = Number(widgetXY.y) + Math.floor((dy * 100) / dZoom.value)
return { left, top } return { left, top }
}, }
attrsChange() {
if (this.dActiveElement.uuid === this.params.uuid && this.svgElements) { function attrsChange() {
for (const element of this.svgElements) { if (dActiveElement.value.uuid === props.params.uuid && svgElements) {
for (const element of svgElements) {
const { item, attrsColor } = element const { item, attrsColor } = element
for (const key in attrsColor) { for (const key in attrsColor) {
if (Object.hasOwnProperty.call(attrsColor, key)) { if (Object.hasOwnProperty.call(attrsColor, key)) {
const color = this.params.colors[attrsColor[key]] const color = props.params.colors[attrsColor[key]]
item.setAttribute(key, color) item.setAttribute(key, color)
} }
} }
} }
} }
},
},
} }
</script> </script>

View File

@ -0,0 +1,54 @@
export type TWSvgSetting = {
name: string,
type: string,
uuid: string
width: number
height: number
colors: [],
left: number
top: number
// zoom: 1.5,
transform: string
radius: number
opacity: number
parent: string
svgUrl: string
setting: [],
record: {
width: number
height: number
minWidth: number
minHeight: number
},
zoom?: number
cropEdit?: boolean
imgUrl?: string
rotate?: number
x?: number
y?: number
}
export const wSvgSetting = {
name: '矢量图形',
type: "w-svg",
uuid: `-1`,
width: 100,
height: 100,
colors: [],
left: 0,
top: 0,
// zoom: 1.5,
transform: '',
radius: 0,
opacity: 1,
parent: '-1',
svgUrl: '',
setting: [],
record: {
width: 0,
height: 0,
minWidth: 10,
minHeight: 10,
},
}

View File

@ -7,22 +7,22 @@
--> -->
<template> <template>
<div id="w-image-style"> <div id="w-image-style">
<el-collapse v-model="activeNames"> <el-collapse v-model="state.activeNames">
<el-collapse-item title="位置尺寸" name="1"> <el-collapse-item title="位置尺寸" name="1">
<div class="line-layout"> <div class="line-layout">
<number-input v-model="innerElement.left" label="X" @finish="(value) => finish('left', value)" /> <number-input v-model="state.innerElement.left" label="X" @finish="(value) => finish('left', value)" />
<number-input v-model="innerElement.top" label="Y" @finish="(value) => finish('top', value)" /> <number-input v-model="state.innerElement.top" label="Y" @finish="(value) => finish('top', value)" />
<number-input v-model="innerElement.width" style="margin-top: 0.5rem" label="宽" @finish="(value) => finish('width', value)" /> <number-input v-model="state.innerElement.width" style="margin-top: 0.5rem" label="宽" @finish="(value) => finish('width', value)" />
<number-input v-model="innerElement.height" style="margin-top: 0.5rem" label="高" @finish="(value) => finish('height', value)" /> <number-input v-model="state.innerElement.height" style="margin-top: 0.5rem" label="高" @finish="(value) => finish('height', value)" />
</div> </div>
</el-collapse-item> </el-collapse-item>
<el-collapse-item title="设置颜色" name="2"> <el-collapse-item title="设置颜色" name="2">
<div v-for="(c, ci) in innerElement.colors" :key="ci + 'c'"> <div v-for="(c, ci) in state.innerElement.colors" :key="ci + 'c'">
<color-select v-model="innerElement.colors[ci]" @finish="(value) => colorFinish('colors')" /> <color-select v-model="state.innerElement.colors[ci]" @finish="(value) => colorFinish('colors')" />
</div> </div>
<br /> <br />
<div class="slide-wrap"> <div class="slide-wrap">
<number-slider v-model="innerElement.opacity" label="不透明" :step="0.01" :maxValue="1" @finish="(value) => finish('opacity', value)" /> <number-slider v-model="state.innerElement.opacity" label="不透明" :step="0.01" :maxValue="1" @finish="(value) => finish('opacity', value)" />
</div> </div>
</el-collapse-item> </el-collapse-item>
<br /> <br />
@ -33,100 +33,139 @@
</div> </div>
</template> </template>
<script> <script lang="ts" setup>
// //
const NAME = 'w-image-style' // const NAME = 'w-image-style'
import { mapGetters, mapActions } from 'vuex' import { reactive, watch } from 'vue'
import { mapGetters, mapActions, useStore } from 'vuex'
import numberInput from '../../settings/numberInput.vue' import numberInput from '../../settings/numberInput.vue'
import iconItemSelect from '../../settings/iconItemSelect.vue' import iconItemSelect, { TIconItemSelectData } from '../../settings/iconItemSelect.vue'
import numberSlider from '../../settings/numberSlider.vue' import numberSlider from '../../settings/numberSlider.vue'
import colorSelect from '../../settings/colorSelect.vue' import colorSelect from '../../settings/colorSelect.vue'
import layerIconList from '@/assets/data/LayerIconList' import layerIconList from '@/assets/data/LayerIconList'
import alignIconList from '@/assets/data/AlignListData' import alignIconList from '@/assets/data/AlignListData'
import { TWSvgSetting, wSvgSetting } from './wSvgSetting'
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
export default { type TState = {
name: NAME, activeNames: string[]
components: { numberInput, numberSlider, iconItemSelect, colorSelect }, innerElement: TWSvgSetting
data() { tag: boolean
return { ingoreKeys: string[]
layerIconList: TIconItemSelectData[]
alignIconList: TIconItemSelectData[]
}
const state = reactive<TState>({
activeNames: ['2', '3', '4'], activeNames: ['2', '3', '4'],
innerElement: {}, innerElement: JSON.parse(JSON.stringify(wSvgSetting)),
tag: false, tag: false,
ingoreKeys: ['left', 'top', 'name', 'width', 'height', 'radiusTopLeft', 'radiusTopRight', 'radiusBottomLeft', 'radiusBottomRight'], ingoreKeys: ['left', 'top', 'name', 'width', 'height', 'radiusTopLeft', 'radiusTopRight', 'radiusBottomLeft', 'radiusBottomRight'],
layerIconList, layerIconList,
alignIconList, alignIconList,
}
},
computed: {
...mapGetters(['dActiveElement', 'dMoving']),
},
watch: {
dActiveElement: {
handler(newValue, oldValue) {
this.change()
},
deep: true,
},
innerElement: {
handler(newValue, oldValue) {
this.changeValue()
},
deep: true,
},
},
created() {
this.change()
},
methods: {
...mapActions(['updateWidgetData', 'updateAlign', 'updateLayerIndex']),
change() {
this.tag = true
this.innerElement = JSON.parse(JSON.stringify(this.dActiveElement))
},
changeValue() {
if (this.tag) {
this.tag = false
return
}
if (this.dMoving) {
return
}
for (let key in this.innerElement) {
if (this.ingoreKeys.indexOf(key) !== -1) {
this.dActiveElement[key] = this.innerElement[key]
} else if (key !== 'setting' && key !== 'record' && this.innerElement[key] !== this.dActiveElement[key]) {
this.updateWidgetData({
uuid: this.dActiveElement.uuid,
key: key,
value: this.innerElement[key],
}) })
const store = useStore()
const {
dActiveElement, dMoving
} = useSetupMapGetters(['dActiveElement', 'dMoving'])
// ...mapGetters(['dActiveElement', 'dMoving']),
watch(
() => dActiveElement.value,
() => {
change()
},
{ deep: true }
)
watch(
() => state.innerElement,
() => {
changeValue()
},
{ deep: true }
)
function created() {
change()
}
created()
// ...mapActions(['updateWidgetData', 'updateAlign', 'updateLayerIndex']),
function change() {
state.tag = true
state.innerElement = JSON.parse(JSON.stringify(dActiveElement.value))
}
function changeValue() {
if (state.tag) {
state.tag = false
return
}
if (dMoving.value) {
return
}
for (let key in state.innerElement) {
const itemKey = key as keyof TWSvgSetting
if (state.ingoreKeys.indexOf(itemKey) !== -1) {
dActiveElement.value[key] = state.innerElement[itemKey]
} else if (itemKey !== 'setting' && itemKey !== 'record' && state.innerElement[itemKey] !== dActiveElement.value[itemKey]) {
store.dispatch("updateWidgetData", {
uuid: dActiveElement.value.uuid,
key: key,
value: state.innerElement[itemKey],
})
// this.updateWidgetData({
// uuid: this.dActiveElement.uuid,
// key: key,
// value: this.innerElement[key],
// })
} }
} }
}, }
colorFinish(key) {
this.finish(key, this.innerElement[key]) function colorFinish(key: keyof TWSvgSetting) {
}, finish(key, state.innerElement[key])
finish(key, value) { }
this.updateWidgetData({
uuid: this.dActiveElement.uuid, function finish(key: string, value: any) {
store.dispatch("updateWidgetData", {
uuid: dActiveElement.value.uuid,
key: key, key: key,
value: value, value: value,
pushHistory: true, pushHistory: true,
}) })
}, // this.updateWidgetData({
layerAction(item) { // uuid: this.dActiveElement.uuid,
this.updateLayerIndex({ // key: key,
uuid: this.dActiveElement.uuid, // value: value,
// pushHistory: true,
// })
}
function layerAction(item: TIconItemSelectData) {
store.dispatch("updateLayerIndex", {
uuid: dActiveElement.value.uuid,
value: item.value, value: item.value,
}) })
}, // this.updateLayerIndex({
alignAction(item) { // uuid: this.dActiveElement.uuid,
this.updateAlign({ // value: item.value,
// })
}
function alignAction(item: TIconItemSelectData) {
store.dispatch("updateAlign", {
align: item.value, align: item.value,
uuid: this.dActiveElement.uuid, uuid: dActiveElement.value.uuid,
}) })
}, // this.updateAlign({
}, // align: item.value,
// uuid: this.dActiveElement.uuid,
// })
} }
</script> </script>

View File

@ -8,8 +8,8 @@
import store from '@/store' import store from '@/store'
import { toRaw } from 'vue' import { toRaw } from 'vue'
export default () => { export default () => {
const collector = new Set() const collector = new Set<string>()
const fonts: any = {} const fonts: Record<string, any> = {}
const { dWidgets: widgets } = store.getters const { dWidgets: widgets } = store.getters
for (let i = 0; i < widgets.length; i++) { for (let i = 0; i < widgets.length; i++) {
const { type, fontClass } = widgets[i] const { type, fontClass } = widgets[i]
@ -18,5 +18,5 @@ export default () => {
fonts[fontClass.id] = toRaw(fontClass) fonts[fontClass.id] = toRaw(fontClass)
} }
} }
return Array.from(collector).map((id: any) => fonts[id]) return Array.from(collector).map((id: string) => fonts[id])
} }

View File

@ -60,6 +60,9 @@ export type TwTextData = {
y: number y: number
} }
}[] }[]
width?: number
height?: number
degree?: number
} }
export const wTextSetting: TwTextData = { export const wTextSetting: TwTextData = {

View File

@ -1,18 +1,18 @@
<template> <template>
<div id="w-text-style"> <div id="w-text-style">
<el-collapse v-model="activeNames"> <el-collapse v-model="state.activeNames">
<el-collapse-item title="位置尺寸" name="1"> <el-collapse-item title="位置尺寸" name="1">
<div class="line-layout"> <div class="line-layout">
<number-input v-model="innerElement.left" label="X" @finish="(value) => finish('left', value)" /> <number-input v-model="state.innerElement.left" label="X" @finish="(value) => finish('left', value)" />
<number-input v-model="innerElement.top" label="Y" @finish="(value) => finish('top', value)" /> <number-input v-model="state.innerElement.top" label="Y" @finish="(value) => finish('top', value)" />
<number-input v-model="innerElement.width" style="margin-top: 0.5rem" label="宽" :editable="true" @finish="(value) => finish('width', value)" /> <number-input v-model="state.innerElement.width" style="margin-top: 0.5rem" label="宽" :editable="true" @finish="(value) => finish('width', value)" />
<number-input v-model="innerElement.height" style="margin-top: 0.5rem" label="高" :editable="true" @finish="(value) => finish('height', value)" /> <number-input v-model="state.innerElement.height" style="margin-top: 0.5rem" label="高" :editable="true" @finish="(value) => finish('height', value)" />
</div> </div>
</el-collapse-item> </el-collapse-item>
<!-- <el-collapse-item title="样式设置" name="2"> --> <!-- <el-collapse-item title="样式设置" name="2"> -->
<div class="line-layout style-item"> <div class="line-layout style-item">
<value-select v-model="innerElement.fontClass" label="文字" :data="fontClassList" inputWidth="152px" :readonly="true" @finish="(font) => finish('fontClass', font)" /> <value-select v-model="state.innerElement.fontClass" label="文字" :data="state.fontClassList" inputWidth="152px" :readonly="true" @finish="(font) => finish('fontClass', font)" />
<value-select v-model="innerElement.fontSize" label="大小" suffix="px" :data="fontSizeList" @finish="(value) => finish('fontSize', value)" /> <value-select v-model="state.innerElement.fontSize" label="大小" suffix="px" :data="state.fontSizeList" @finish="(value) => finish('fontSize', value)" />
</div> </div>
<icon-item-select class="style-item" :data="styleIconList1" @finish="textStyleAction" /> <icon-item-select class="style-item" :data="styleIconList1" @finish="textStyleAction" />
@ -24,61 +24,73 @@
</div> --> </div> -->
<!-- <el-collapse-item title="位置尺寸" name="1"> --> <!-- <el-collapse-item title="位置尺寸" name="1"> -->
<div class="style-item slide-wrap"> <div class="style-item slide-wrap">
<number-slider v-model="innerElement.letterSpacing" style="font-size: 14px" label="字距" labelWidth="40px" :step="0.05" :minValue="-innerElement.fontSize" :maxValue="innerElement.fontSize * 2" @finish="(value) => finish('letterSpacing', value)" /> <number-slider v-model="state.innerElement.letterSpacing" style="font-size: 14px" label="字距" labelWidth="40px" :step="0.05" :minValue="-state.innerElement.fontSize" :maxValue="state.innerElement.fontSize * 2" @finish="(value) => finish('letterSpacing', value)" />
<number-slider v-model="innerElement.lineHeight" style="font-size: 14px" label="行距" labelWidth="40px" :step="0.05" :minValue="0" :maxValue="2.5" @finish="(value) => finish('lineHeight', value)" /> <number-slider v-model="state.innerElement.lineHeight" style="font-size: 14px" label="行距" labelWidth="40px" :step="0.05" :minValue="0" :maxValue="2.5" @finish="(value) => finish('lineHeight', value)" />
</div> </div>
<!-- </el-collapse-item> --> <!-- </el-collapse-item> -->
<div style="flex-wrap: nowrap" class="line-layout style-item"> <div style="flex-wrap: nowrap" class="line-layout style-item">
<color-select v-model="innerElement.color" label="颜色" @finish="(value) => finish('color', value)" /> <color-select v-model="state.innerElement.color" label="颜色" @finish="(value) => finish('color', value)" />
<!-- <color-select v-model="innerElement.backgroundColor" label="背景颜色" @finish="(value) => finish('backgroundColor', value)" /> --> <!-- <color-select v-model="innerElement.backgroundColor" label="背景颜色" @finish="(value) => finish('backgroundColor', value)" /> -->
</div> </div>
<div class="line-layout style-item"> <div class="line-layout style-item">
<effect-wrap v-model="innerElement.textEffects" :data="innerElement" :degree="innerElement.degree" @select="selectTextEffect" /> <effect-wrap v-model="state.innerElement.textEffects" :data="state.innerElement" :degree="state.innerElement.degree" @select="selectTextEffect" />
</div> </div>
<icon-item-select class="style-item" :data="layerIconList" @finish="layerAction" /> <icon-item-select class="style-item" :data="layerIconList" @finish="layerAction" />
<icon-item-select class="style-item" :data="alignIconList" @finish="alignAction" /> <icon-item-select class="style-item" :data="alignIconList" @finish="alignAction" />
<!-- v-show="!innerElement.editable" --> <!-- v-show="!innerElement.editable" -->
<div style="margin-top: 10px" class="line-layout style-item"> <div style="margin-top: 10px" class="line-layout style-item">
<text-input-area v-model="innerElement.text" @finish="(value) => finish('text', value)" /> <text-input-area v-model="state.innerElement.text" @finish="(value) => finish('text', value)" />
</div> </div>
<!-- </el-collapse-item> --> <!-- </el-collapse-item> -->
</el-collapse> </el-collapse>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
// //
const NAME = 'w-text-style' const NAME = 'w-text-style'
import { defineComponent, reactive, toRefs, computed, watch, nextTick, onMounted } from 'vue' import { defineComponent, reactive, toRefs, computed, watch, nextTick, onMounted } from 'vue'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { styleIconList1, styleIconList2, alignIconList } from '@/assets/data/TextIconsData' import { styleIconList1, styleIconList2, alignIconList, TStyleIconData, TStyleIconData2 } from '@/assets/data/TextIconsData'
import layerIconList from '@/assets/data/LayerIconList' import layerIconList from '@/assets/data/LayerIconList'
import numberInput from '../../settings/numberInput.vue' import numberInput from '../../settings/numberInput.vue'
import numberSlider from '../../settings/numberSlider.vue' import numberSlider from '../../settings/numberSlider.vue'
import colorSelect from '../../settings/colorSelect.vue' import colorSelect from '../../settings/colorSelect.vue'
import iconItemSelect from '../../settings/iconItemSelect.vue' import iconItemSelect, { TIconItemSelectData } from '../../settings/iconItemSelect.vue'
import textInputArea from '../../settings/textInputArea.vue' import textInputArea from '../../settings/textInputArea.vue'
import valueSelect from '../../settings/valueSelect.vue' import valueSelect from '../../settings/valueSelect.vue'
import effectWrap from '../../settings/EffectSelect/TextWrap.vue' import effectWrap from '../../settings/EffectSelect/TextWrap.vue'
import { useFontStore } from '@/common/methods/fonts' import { useFontStore } from '@/common/methods/fonts'
import usePageFontsFilter from './pageFontsFilter.ts' import usePageFontsFilter from './pageFontsFilter'
import { wTextSetting ,TwTextData } from './wTextSetting';
type TState = {
activeNames: string[],
innerElement: TwTextData,
tag: boolean,
ingoreKeys: string[],
fontSizeList: number[],
fontClassList: Record<string, any>, //
lineHeightList: number[],
letterSpacingList: number[],
layerIconList: TIconItemSelectData[],
styleIconList1: TStyleIconData[],
styleIconList2: TStyleIconData2[],
alignIconList: TIconItemSelectData[],
}
export default defineComponent({
name: NAME,
components: { numberInput, colorSelect, iconItemSelect, textInputArea, valueSelect, effectWrap, numberSlider },
setup() {
const store = useStore() const store = useStore()
const route = useRoute() const route = useRoute()
const state = reactive({ const state = reactive<TState>({
activeNames: [], activeNames: [],
innerElement: {}, innerElement: JSON.parse(JSON.stringify(wTextSetting)),
tag: false, tag: false,
ingoreKeys: ['left', 'top', 'name', 'width', 'height', 'text', 'color', 'backgroundColor'], ingoreKeys: ['left', 'top', 'name', 'width', 'height', 'text', 'color', 'backgroundColor'],
fontSizeList: [12, 14, 24, 26, 28, 30, 36, 48, 60, 72, 96, 108, 120, 140, 180, 200, 250, 300, 400, 500], fontSizeList: [12, 14, 24, 26, 28, 30, 36, 48, 60, 72, 96, 108, 120, 140, 180, 200, 250, 300, 400, 500],
fontClassList: [], // fontClassList: {}, //
lineHeightList: [1, 1.5, 2], lineHeightList: [1, 1.5, 2],
letterSpacingList: [0, 10, 25, 50, 75, 100, 200], letterSpacingList: [0, 10, 25, 50, 75, 100, 200],
layerIconList, layerIconList,
@ -98,7 +110,7 @@ export default defineComponent({
changeValue() changeValue()
}, { deep: true }) }, { deep: true })
let timer: any = null let timer: boolean | null = null
onMounted(() => { onMounted(() => {
change() change()
@ -130,14 +142,15 @@ export default defineComponent({
} }
// TODO // TODO
for (let key in state.innerElement) { for (let key in state.innerElement) {
if (state.ingoreKeys.indexOf(key) !== -1) { const itemKey = key as keyof TwTextData
dActiveElement.value[key] = state.innerElement[key] if (state.ingoreKeys.indexOf(itemKey) !== -1) {
} else if (key !== 'setting' && key !== 'record' && state.innerElement[key] !== dActiveElement.value[key]) { dActiveElement.value[itemKey] = state.innerElement[itemKey]
} else if (key !== 'setting' && key !== 'record' && state.innerElement[itemKey] !== dActiveElement.value[itemKey]) {
// const pushHistory = !['textEffects', 'transformData', 'fontClass'].includes(key) // const pushHistory = !['textEffects', 'transformData', 'fontClass'].includes(key)
store.dispatch('updateWidgetData', { store.dispatch('updateWidgetData', {
uuid: dActiveElement.value.uuid, uuid: dActiveElement.value.uuid,
key, key,
value: state.innerElement[key], value: state.innerElement[itemKey],
pushHistory: false, pushHistory: false,
}) })
} }
@ -154,7 +167,7 @@ export default defineComponent({
function loadFonts() { function loadFonts() {
const localFonts = useFontStore.list const localFonts = useFontStore.list
const fontLists = { 当前页面: [], 中文: [], 英文: [] } const fontLists: Record<string, any> = { 当前页面: [], 中文: [], 英文: [] }
for (const font of localFonts) { for (const font of localFonts) {
const { id, oid, value, url, alias, preview, lang } = font const { id, oid, value, url, alias, preview, lang } = font
const item = { id, oid, value, url, alias, preview } const item = { id, oid, value, url, alias, preview }
@ -164,7 +177,7 @@ export default defineComponent({
state.fontClassList = fontLists state.fontClassList = fontLists
} }
function finish(key, value) { function finish(key: string, value: number | Record<string, any> | string) {
store.dispatch('updateWidgetData', { store.dispatch('updateWidgetData', {
uuid: dActiveElement.value.uuid, uuid: dActiveElement.value.uuid,
key, key,
@ -176,23 +189,23 @@ export default defineComponent({
}, 300) }, 300)
} }
function layerAction(item) { function layerAction(item: TIconItemSelectData) {
store.dispatch('updateLayerIndex', { store.dispatch('updateLayerIndex', {
uuid: dActiveElement.value.uuid, uuid: dActiveElement.value.uuid,
value: item.value, value: item.value,
}) })
} }
async function textStyleAction(item) { async function textStyleAction(item: TIconItemSelectData) {
let value = item.key === 'textAlign' ? item.value : item.value[item.select ? 1 : 0] let value = item.key === 'textAlign' ? item.value : (item.value as number[])[item.select ? 1 : 0];
state.innerElement[item.key] = value (state.innerElement as Record<string, any>)[item.key || ""] = value
// TODO: // TODO:
item.key === 'writingMode' && relationChange() item.key === 'writingMode' && relationChange()
await nextTick() await nextTick()
store.commit('updateRect') store.commit('updateRect')
} }
async function alignAction(item) { async function alignAction(item: TIconItemSelectData) {
store.dispatch('updateAlign', { store.dispatch('updateAlign', {
align: item.value, align: item.value,
uuid: dActiveElement.value.uuid, uuid: dActiveElement.value.uuid,
@ -241,15 +254,12 @@ export default defineComponent({
}, 10) }, 10)
} }
return { defineExpose({
...toRefs(state),
selectTextEffect, selectTextEffect,
textStyleAction, textStyleAction,
finish, finish,
layerAction, layerAction,
alignAction alignAction
}
}
}) })
</script> </script>