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

Feat: Convert panel/wrap components to composition API
This commit is contained in:
Jeremy Yu 2024-03-06 23:03:15 +00:00 committed by GitHub
commit 05cde577b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 530 additions and 402 deletions

View File

@ -15,22 +15,31 @@ type IGetTempListParam = {
search: string
page: number
pageSize: number
cate:number
cate: number | string
}
type IGetTempListData = {
export type IGetTempListData = {
cover: string
height: number
id: number
state: number
title: string
width: number
isDelect: boolean
fail: boolean
top: number
left: number
data?: string
}
type IGetTempListResult = TCommResResult<IGetTempListData>
type IGetTempListResult = TPageRequestResult<IGetTempListData[]>
// 获取模板列表
export const getTempList = (params: IGetTempListParam) => fetch<IGetTempListResult>('design/list', params, 'get')
export const getTempDetail = (params: Type.Object = {}) => fetch('design/temp', params, 'get')
type TGetTempDetail = {
id: number
}
export const getTempDetail = (params: TGetTempDetail) => fetch<{data: string}>('design/temp', params, 'get')
type TGetCategoriesParams = {
type?: number

View File

@ -13,9 +13,16 @@ export type TItem2DataParam = {
height: number
url: string
model?: string
canvasWidth?: number
}
export default async function setItem2Data(item: TItem2DataParam) {
export type TItem2DataResult = {
width: number
height: number
canvasWidth: number
}
export default async function setItem2Data(item: TItem2DataParam): Promise<Required<TItem2DataParam>> {
const cloneItem = JSON.parse(JSON.stringify(item))
const { width: screenWidth, height: screenHeight } = store.getters.dPage
let { width: imgWidth, height: imgHeight } = item

View File

@ -0,0 +1,24 @@
type TCommonImgListData = {
isDelect: boolean
cover: string
fail: boolean
top: number
left: number
width: number
height: number
title: string
}
type TCommonPhotoListData = {
listWidth: number
gap: number
thumb?: string
url: string
color: string
isDelect: boolean
width: number
height: number
model: string
}

View File

@ -2,137 +2,148 @@
* @Author: ShawnPhang
* @Date: 2021-08-27 15:16:07
* @Description: 模板列表
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-11-22 09:55:59
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
* @Date: 2024-03-06 21:16:00
-->
<template>
<div class="wrap">
<search-header v-model="searchKeyword" @change="cateChange" />
<el-divider v-show="title" style="margin-top: 1.7rem" content-position="left">
<span style="font-weight: bold">{{ title }}</span>
<search-header v-model="state.searchKeyword" @change="cateChange" />
<el-divider v-show="state.title" style="margin-top: 1.7rem" content-position="left">
<span style="font-weight: bold">{{ state.title }}</span>
</el-divider>
<ul ref="listRef" v-infinite-scroll="load" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto">
<img-water-fall :listData="list" @select="selectItem" />
<div v-show="loading" class="loading"><i class="el-icon-loading"></i> 拼命加载中</div>
<div v-show="loadDone" class="loading">全部加载完毕</div>
<img-water-fall :listData="state.list" @select="selectItem" />
<div v-show="state.loading" class="loading"><i class="el-icon-loading"></i> 拼命加载中</div>
<div v-show="state.loadDone" class="loading">全部加载完毕</div>
</ul>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, onMounted, ref } from 'vue'
<script lang="ts" setup>
import { reactive, ref, defineExpose } from 'vue'
import api from '@/api'
import { mapActions, mapGetters, useStore } from 'vuex'
import { useRoute } from 'vue-router'
import { useStore } from 'vuex'
import { LocationQueryValue, useRoute, useRouter } from 'vue-router'
// import chooseType from './components/chooseType.vue'
// import editModel from './components/editModel.vue'
import searchHeader from './components/searchHeader.vue'
import useConfirm from '@/common/methods/confirm'
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
import imgWaterFall from './components/imgWaterFall.vue'
import { IGetTempListData } from '@/api/home'
export default defineComponent({
components: { searchHeader },
setup() {
const listRef = ref(null)
const route = useRoute()
const store = useStore()
const state: any = reactive({
loading: false,
loadDone: false,
list: [],
title: '推荐模板',
searchKeyword: '',
})
const pageOptions: any = { page: 0, pageSize: 20, cate: 1 }
const { cate, edit } = route.query
cate && (pageOptions.cate = cate)
edit && store.commit('managerEdit', true)
type TState = {
loading: boolean
loadDone: boolean
list: IGetTempListData[]
title: string
searchKeyword: string
}
// onMounted(async () => {})
type TPageOptions = {
page: number,
pageSize: number,
cate: number | string
state?: string
}
const load = async (init: boolean = false, stat?: string) => {
stat && (pageOptions.state = stat)
const listRef = ref<HTMLElement | null>(null)
const route = useRoute()
const router = useRouter()
const store = useStore()
const state = reactive<TState>({
loading: false,
loadDone: false,
list: [],
title: '推荐模板',
searchKeyword: '',
})
if (init) {
listRef.value.scrollTop = 0
state.list = []
pageOptions.page = 0
state.loadDone = false
}
if (state.loadDone || state.loading) {
return
}
const { tempEditing, dHistoryParams } = useSetupMapGetters(['tempEditing', 'dHistoryParams'])
state.loading = true
pageOptions.page += 1
const pageOptions: TPageOptions = { page: 0, pageSize: 20, cate: 1 }
const { cate, edit } = route.query
cate && (pageOptions.cate = (cate as LocationQueryValue) || 1)
edit && store.commit('managerEdit', true)
const res = await api.home.getTempList({ search: state.searchKeyword, ...pageOptions })
res.list.length <= 0 && (state.loadDone = true)
state.list = state.list.concat(res.list)
// onMounted(async () => {})
setTimeout(() => {
state.loading = false
checkHeight()
}, 100)
const load = async (init: boolean = false, stat?: string) => {
stat && (pageOptions.state = stat)
if (init && listRef.value) {
listRef.value.scrollTop = 0
state.list = []
pageOptions.page = 0
state.loadDone = false
}
if (state.loadDone || state.loading) {
return
}
state.loading = true
pageOptions.page += 1
const res = await api.home.getTempList({ search: state.searchKeyword, ...pageOptions })
res.list.length <= 0 && (state.loadDone = true)
state.list = state.list.concat(res.list)
setTimeout(() => {
state.loading = false
checkHeight()
}, 100)
}
function cateChange(type: any) {
state.title = type.name
const init = pageOptions.cate != type.id
pageOptions.cate = type.id
load(init, pageOptions.state)
}
function checkHeight() {
if (!listRef.value) return
//
const isLess = listRef.value.offsetHeight > (listRef.value.firstElementChild as HTMLElement)?.offsetHeight
isLess && load()
}
// ...mapActions(['selectWidget', 'updatePageData', 'setTemplate', 'pushHistory']),
async function selectItem(item: IGetTempListData) {
store.commit('setShowMoveable', false) //
if (dHistoryParams.value.length > 0) {
const isPass = await useConfirm('提示', '使用模板后,当前页面将会被替换,是否继续', 'warning')
if (!isPass) {
return false
}
}
store.commit('managerEdit', false)
store.commit('setDWidgets', [])
function cateChange(type: any) {
state.title = type.name
const init = pageOptions.cate != type.id
pageOptions.cate = type.id
load(init, pageOptions.stat)
}
setTempId(item.id)
function checkHeight() {
//
const isLess = listRef.value.offsetHeight > listRef.value.firstElementChild.offsetHeight
isLess && load()
}
let result = null
if (!item.data) {
const res = await api.home.getTempDetail({ id: item.id })
result = JSON.parse(res.data)
} else {
result = JSON.parse(item.data)
}
const { page, widgets } = result
console.log(widgets)
return {
...toRefs(state),
load,
cateChange,
listRef,
}
},
computed: {
...mapGetters(['tempEditing', 'dHistoryParams']),
},
methods: {
...mapActions(['selectWidget', 'updatePageData', 'setTemplate', 'pushHistory']),
async selectItem(item: any) {
this.$store.commit('setShowMoveable', false) //
if (this.dHistoryParams.length > 0) {
const isPass = await useConfirm('提示', '使用模板后,当前页面将会被替换,是否继续', 'warning')
if (!isPass) {
return false
}
}
this.$store.commit('managerEdit', false)
this.$store.commit('setDWidgets', [])
this.setTempId(item.id)
let result = null
if (!item.data) {
const res = await api.home.getTempDetail({ id: item.id })
result = JSON.parse(res.data)
} else {
result = JSON.parse(item.data)
}
const { page, widgets } = result
console.log(widgets)
this.$store.commit('setDPage', page)
this.setTemplate(widgets)
setTimeout(() => {
this.$store.commit('zoomScreenChange')
}, 300)
this.selectWidget({
uuid: '-1',
})
},
store.commit('setDPage', page)
store.dispatch('setTemplate', widgets)
// setTemplate(widgets)
setTimeout(() => {
store.commit('zoomScreenChange')
}, 300)
store.dispatch('selectWidget', {
uuid: '-1'
})
// selectWidget({
// uuid: '-1',
// })
}
// action({ name, value }: any, item: any, index: number) {
// switch (name) {
// case 'edit':
@ -158,12 +169,17 @@ export default defineComponent({
// setTempStat({ id }: any, stat: string) {
// api.home.setTempStat({ id, stat })
// },
setTempId(tempId: number | string) {
const { id } = this.$route.query
this.$router.push({ path: '/home', query: { tempid: tempId, id }, replace: true })
},
},
function setTempId(tempId: number | string) {
const { id } = route.query
router.push({ path: '/home', query: { tempid: tempId, id }, replace: true })
}
defineExpose({
load,
cateChange,
listRef,
})
</script>
<style lang="less" scoped>

View File

@ -2,8 +2,8 @@
* @Author: ShawnPhang
* @Date: 2023-10-04 02:04:04
* @Description: 列表分类头部
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-10-04 02:30:59
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
* @Date: 2024-03-06 21:16:00
-->
<template>
<div v-if="!isBack" class="content__wrap">
@ -21,22 +21,34 @@
</span>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script lang="ts" setup>
import { defineProps, defineEmits } from 'vue'
export default defineComponent({
props: ['types', 'isBack'],
emits: ['select', 'back'],
setup(props, { emit }) {
const select = (item: any) => {
emit('select', item)
}
const back = () => {
emit('back')
}
return { select, back }
},
})
export type TClassHeaderTypeData = {
name: string
}
type TProps = {
types: TClassHeaderTypeData[]
isBack: boolean
}
type TEmits = {
(event: 'select', data: string[]): void
(event: 'back'): void
}
const { types, isBack } = defineProps<TProps>()
const emit = defineEmits<TEmits>()
const select = (item: any) => {
emit('select', item)
}
const back = () => {
emit('back')
}
defineExpose({ select, back })
</script>
<style lang="less" scoped>

View File

@ -2,8 +2,8 @@
* @Author: ShawnPhang
* @Date: 2023-10-04 19:12:40
* @Description: 图片描述ToolTip
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-10-04 22:51:06
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
* @Date: 2024-03-06 21:16:00
-->
<template>
<el-tooltip :disabled="!detail.author" :offset="1" effect="light" placement="bottom-start" :hide-after="0" :enterable="false" raw-content>
@ -17,15 +17,18 @@
</el-tooltip>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script lang="ts" setup>
import { defineProps } from 'vue'
export type TImageTipDetailData = {
author: string
description: string
}
type Tprops = {
detail: TImageTipDetailData
}
const { detail } = defineProps<Tprops>()
export default defineComponent({
props: {
detail: {},
},
setup() {
return {}
},
})
</script>

View File

@ -2,14 +2,18 @@
* @Author: ShawnPhang
* @Date: 2021-12-16 16:20:16
* @Description: 瀑布流组件
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-12-11 11:45:24
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
* @Date: 2024-03-06 21:16:00
-->
<template>
<div ref="imgWaterFall" :style="{ height: countHeight + 'px' }" class="img-water-fall">
<div ref="imgWaterFall" :style="{ height: state.countHeight + 'px' }" class="img-water-fall">
<!-- backgroundImage: `url(${item.cover})` -->
<div v-for="(item, i) in list" :key="i + 'iwf'" :style="{ top: item.top + 'px', left: item.left + 'px', width: width + 'px', height: item.height + 'px' }" class="img-box" @click.stop="selectItem(item, i)">
<edit-model v-if="edit" :options="edit" :data="{ item, i }">
<div
v-for="(item, i) in state.list" :key="i + 'iwf'"
:style="{ top: item.top + 'px', left: item.left + 'px', width: state.width + 'px', height: item.height + 'px' }"
class="img-box" @click.stop="selectItem(item, i)"
>
<edit-model v-if="edit" :options="props.edit" :data="{ item, i }">
{{ item.isDelect }}
<div v-if="item.isDelect" class="list__mask">已删除</div>
<el-image v-if="!item.fail" class="img" :src="item.cover" lazy loading="lazy" @error="loadError(item)" />
@ -20,76 +24,82 @@
</div>
</template>
<script>
const NAME = 'img-water-fall'
import { defineComponent, toRefs, reactive, watch } from 'vue'
<script lang="ts" setup>
// const NAME = 'img-water-fall'
import { IGetTempListData } from '@/api/home';
import { reactive, watch, defineProps, defineExpose, defineEmits } from 'vue'
export default defineComponent({
name: NAME,
props: {
listData: {
type: Array,
required: true,
},
edit: {}
type TProps = {
listData: IGetTempListData[]
edit?: Record<string, any>
}
type TState = {
width: number
countHeight: number
list: IGetTempListData[]
}
type TEmits = {
(event: 'select', data: IGetTempListData): void
(event: 'load'): void
}
const props = defineProps<TProps>()
const emit = defineEmits<TEmits>()
const state = reactive<TState>({
width: 146, //
list: [],
countHeight: 0,
})
const columnHeights: number[] = [] //
const columnNums = 2 //
const gap = 7 //
watch(
() => props.listData,
() => {
columnHeights.length = 0
const widthLimit = state.width * columnNums // + gap * (columnNums - 1) // 每行宽度
const cloneList = JSON.parse(JSON.stringify(props.listData))
for (let i = 0; i < cloneList.length; i++) {
let index = i % columnNums
const item = cloneList[i]
item.height = (item.height / item.width) * state.width //
item.left = index * (widthLimit / columnNums + gap) //
item.top = columnHeights[index] + gap || 0 //
// columnHeights[index] = isNaN(columnHeights[index]) ? item.height : item.height + columnHeights[index] + gap //
//
if (isNaN(columnHeights[index])) {
columnHeights[index] = item.height
} else {
index = columnHeights.indexOf(Math.min(...columnHeights))
item.left = index * (widthLimit / columnNums + gap)
item.top = columnHeights[index] + gap || 0
columnHeights[index] = item.height + columnHeights[index] + gap
}
}
state.countHeight = Math.max(...columnHeights)
state.list = cloneList
},
emits: ['select', 'load'],
setup(props, { emit }) {
const state = reactive({
width: 146, //
list: [],
countHeight: 0,
})
)
const columnHeights = [] //
const columnNums = 2 //
const gap = 7 //
const load = () => {
emit('load')
}
const selectItem = (value: IGetTempListData, index: number) => {
emit('select', value)
}
const loadError = (item: IGetTempListData) => {
item.fail = true
}
watch(
() => props.listData,
() => {
columnHeights.length = 0
const widthLimit = state.width * columnNums // + gap * (columnNums - 1) // 每行宽度
const cloneList = JSON.parse(JSON.stringify(props.listData))
for (let i = 0; i < cloneList.length; i++) {
let index = i % columnNums
const item = cloneList[i]
item.height = (item.height / item.width) * state.width //
item.left = index * (widthLimit / columnNums + gap) //
item.top = columnHeights[index] + gap || 0 //
// columnHeights[index] = isNaN(columnHeights[index]) ? item.height : item.height + columnHeights[index] + gap //
//
if (isNaN(columnHeights[index])) {
columnHeights[index] = item.height
} else {
index = columnHeights.indexOf(Math.min(...columnHeights))
item.left = index * (widthLimit / columnNums + gap)
item.top = columnHeights[index] + gap || 0
columnHeights[index] = item.height + columnHeights[index] + gap
}
}
state.countHeight = Math.max(...columnHeights)
state.list = cloneList
},
)
const load = () => {
emit('load')
}
const selectItem = (value, index) => {
emit('select', value)
}
const loadError = (item) => {
item.fail = true
}
return {
...toRefs(state),
load,
selectItem,
loadError,
}
},
defineExpose({
load,
selectItem,
loadError,
})
</script>

View File

@ -2,13 +2,22 @@
* @Author: ShawnPhang
* @Date: 2022-02-23 15:48:52
* @Description: 图片列表组件 Bookshelf Layout
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-02-29 16:52:37
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
* @Date: 2024-03-06 21:16:00
-->
<template>
<ul ref="listRef" class="img-list-wrap" :style="{ paddingBottom: isShort ? '15px' : '200px' }" @scroll="scrollEvent($event)">
<div class="list">
<div v-for="(item, i) in list" :key="i + 'i'" :style="{ width: item.listWidth + 'px', marginRight: item.gap + 'px' }" class="list__img" draggable="false" @mousedown="dragStart($event, i)" @mousemove="mousemove" @mouseup="mouseup" @click.stop="select(i)" @dragstart="dragStart($event, i)">
<div
v-for="(item, i) in state.list" :key="i + 'i'"
:style="{ width: item.listWidth + 'px', marginRight: item.gap + 'px' }"
class="list__img" draggable="false"
@mousedown="dragStart($event, i)"
@mousemove="mousemove"
@mouseup="mouseup"
@click.stop="select(i)"
@dragstart="dragStart($event, i)"
>
<edit-model v-if="edit" :options="edit" :data="{ item, i }">
<div v-if="item.isDelect" class="list__mask">已删除</div>
<el-image class="img transparent-bg" :src="item.thumb || item.url" :style="{ height: getInnerHeight(item) + 'px' }" lazy loading="lazy" />
@ -24,163 +33,182 @@
</template>
</div>
</div>
<div v-if="!isDone" v-show="loading" class="loading"><i class="el-icon-loading" /> 拼命加载中</div>
<div v-if="!isDone" v-show="state.loading" class="loading"><i class="el-icon-loading" /> 拼命加载中</div>
<div v-else class="loading">全部加载完毕</div>
</ul>
</template>
<script lang="ts">
import { defineComponent, toRefs, reactive, watch, nextTick } from 'vue'
<script lang="ts" setup>
import { reactive, watch, nextTick, defineProps, defineExpose, defineEmits, ref } from 'vue'
import DragHelper from '@/common/hooks/dragHelper'
import setImageData from '@/common/methods/DesignFeatures/setImage'
import setImageData, { TItem2DataParam } from '@/common/methods/DesignFeatures/setImage'
export default defineComponent({
props: {
listData: {},
edit: {},
isDone: {},
isShort: {
default: false,
},
},
emits: ['load', 'drag', 'select'],
setup(props, context) {
const state: any = reactive({
loading: true,
list: [],
listRef: null,
})
type TProps = {
listData: TCommonPhotoListData[]
edit: Record<string, any>
isDone: Record<string, any>
isShort: boolean
}
const dragHelper = new DragHelper()
let isDrag = false
let startPoint = { x: 99999, y: 99999 }
const mouseup = (e: any) => {
e.preventDefault()
setTimeout(() => {
isDrag = false
startPoint = { x: 99999, y: 99999 }
}, 10)
type TEmits = {
(event: 'load'): void
(event: 'select', data: number): void
(event: 'drag', data: number): void
}
type TState = {
loading: boolean
list: TCommonPhotoListData[]
}
const { listData, edit, isDone, isShort } = withDefaults(defineProps<TProps>(), {
isShort: false
})
const emit = defineEmits<TEmits>()
const listRef = ref<HTMLElement | null>(null)
const state = reactive<TState>({
loading: true,
list: [],
})
const dragHelper = new DragHelper()
let isDrag = false
let startPoint = { x: 99999, y: 99999 }
const mouseup = (e: MouseEvent) => {
e.preventDefault()
setTimeout(() => {
isDrag = false
startPoint = { x: 99999, y: 99999 }
}, 10)
}
const mousemove = (e: MouseEvent) => {
e.preventDefault()
if (e.x - startPoint.x > 2 || e.y - startPoint.y > 2) {
isDrag = true
}
}
watch(
() => listData,
async (newList: TCommonPhotoListData[], oldList: TCommonPhotoListData[]) => {
!oldList && (oldList = [])
if (newList.length <= 0) {
state.list.length = 0
return
}
const mousemove = (e: any) => {
e.preventDefault()
if (e.x - startPoint.x > 2 || e.y - startPoint.y > 2) {
isDrag = true
}
}
watch(
() => props.listData,
async (newList: any, oldList: any) => {
!oldList && (oldList = [])
if (newList.length <= 0) {
state.list.length = 0
let list = newList.filter((v: TCommonPhotoListData) => !newList.includes(v) || !oldList.includes(v)) // difference
list = JSON.parse(JSON.stringify(list))
const marginRight = 6 //
const limitWidth = (await getFatherWidth()) - marginRight
const standardHeight = 280 //
const neatArr: TCommonPhotoListData[][] = [] //
function factory(cutArr: TCommonPhotoListData[]) {
return new Promise<{ height: number, list: TCommonPhotoListData[] }>((resolve) => {
const lineup = list.shift()
if (!lineup) {
resolve({ height: calculate(cutArr), list: cutArr })
return
}
let list = newList.filter((v: any) => !newList.includes(v) || !oldList.includes(v)) // difference
list = JSON.parse(JSON.stringify(list))
const marginRight = 6 //
const limitWidth = (await getFatherWidth()) - marginRight
const standardHeight = 280 //
const neatArr: any = [] //
function factory(cutArr: any) {
return new Promise((resolve) => {
const lineup = list.shift()
if (!lineup) {
resolve({ height: calculate(cutArr), list: cutArr })
return
}
cutArr.push(lineup)
const finalHeight = calculate(cutArr)
if (finalHeight > standardHeight) {
resolve(factory(cutArr))
} else {
resolve({ height: finalHeight, list: cutArr })
}
})
}
function calculate(cutArr: any) {
let cumulate = 0
for (const iterator of cutArr) {
const { width, height } = iterator
cumulate += width / height
}
return (limitWidth - marginRight * (cutArr.length - 1)) / cumulate
}
async function handleList() {
if (list.length <= 0) {
return
}
const { list: newList, height }: any = await factory([list.shift()])
neatArr.push(
newList.map((x: any, index) => {
x.listWidth = (x.width / x.height) * height
x.gap = index !== newList.length - 1 ? marginRight : 0
return x
}),
)
if (list.length > 0) {
await handleList()
}
cutArr.push(lineup)
const finalHeight = calculate(cutArr)
if (finalHeight > standardHeight) {
resolve(factory(cutArr))
} else {
resolve({ height: finalHeight, list: cutArr })
}
})
}
function calculate(cutArr: TCommonPhotoListData[]) {
let cumulate = 0
for (const iterator of cutArr) {
const { width, height } = iterator
cumulate += width / height
}
return (limitWidth - marginRight * (cutArr.length - 1)) / cumulate
}
async function handleList() {
if (list.length <= 0) {
return
}
const { list: newList, height } = await factory([(list.shift() as TCommonPhotoListData)])
neatArr.push(
newList.map((x: TCommonPhotoListData, index: number) => {
x.listWidth = (x.width / x.height) * height
x.gap = index !== newList.length - 1 ? marginRight : 0
return x
}),
)
if (list.length > 0) {
await handleList()
state.list = state.list.concat(neatArr.flat(1))
state.loading = false
},
)
async function getFatherWidth() {
await nextTick()
const dom = state.listRef
const father = dom.parentElement || dom.parentNode
return father.offsetWidth
}
function getRef() {
// ref
return state.listRef
}
const load = () => {
state.loading = true
context.emit('load')
}
const select = (i: number) => {
!isDrag && !state.list[i].isDelect && context.emit('select', i)
}
const dragStart = async (e: Event | any, i: number) => {
e.preventDefault()
startPoint = { x: e.x, y: e.y }
if (!state.list[i].isDelect) {
const img = await setImageData(state.list[i])
dragHelper.start(e, img.canvasWidth)
context.emit('drag', i)
}
}
function delItem(i: number) {
state.list[i].isDelect = true
}
const scrollEvent = (e: any) => {
if (e.target.scrollTop + e.target.offsetHeight + 200 >= e.target.scrollHeight) {
load()
}
}
const getInnerHeight = ({ height, listWidth, width }: any) => (height * listWidth) / width
return {
load,
dragStart,
select,
...toRefs(state),
delItem,
scrollEvent,
getRef,
mouseup,
mousemove,
getInnerHeight,
}
await handleList()
state.list = state.list.concat(neatArr.flat(1))
state.loading = false
},
)
async function getFatherWidth() {
await nextTick()
if (!listRef.value) return 0
const father = listRef.value.parentElement || listRef.value.parentNode
if (!father) return 0
return (father as HTMLElement).offsetWidth
}
function getRef() {
// ref
return listRef
}
const load = () => {
state.loading = true
emit('load')
}
const select = (i: number) => {
!isDrag && !state.list[i].isDelect && emit('select', i)
}
const dragStart = async (e: Event | any, i: number) => {
e.preventDefault()
startPoint = { x: e.x, y: e.y }
if (!state.list[i].isDelect) {
const setImageParams: TItem2DataParam = {
width: state.list[i].width,
height: state.list[i].height,
url: state.list[i].url || '',
model: state.list[i].model
}
const img = await setImageData(setImageParams)
dragHelper.start(e, img.canvasWidth)
emit('drag', i)
}
}
function delItem(i: number) {
state.list[i].isDelect = true
}
const scrollEvent = (e: any) => {
if (e.target.scrollTop + e.target.offsetHeight + 200 >= e.target.scrollHeight) {
load()
}
}
const getInnerHeight = ({ height, listWidth, width }: any) => (height * listWidth) / width
defineExpose({
load,
dragStart,
select,
delItem,
scrollEvent,
getRef,
mouseup,
mousemove,
getInnerHeight,
})
</script>

View File

@ -2,8 +2,8 @@
* @Author: ShawnPhang
* @Date: 2022-01-27 11:05:48
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-10-04 01:53:10
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
* @Date: 2024-03-06 21:16:00
-->
<template>
<div class="search__wrap">
@ -11,66 +11,85 @@
<div class="search__type"><i class="iconfont icon-ego-caidan" /></div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="type in materialCates" :key="type.id" @click="action('change', type, type.id)">
<span :class="['cate__text', { 'cate--select': +currentIndex === type.id }]">{{ type.name }}</span>
<el-dropdown-item
v-for="type in state.materialCates" :key="type.id"
@click="action('change', type, type.id)"
>
<span :class="['cate__text', { 'cate--select': + state.currentIndex === type.id }]">{{ type.name }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<span v-else style="width: 1rem"></span>
<el-input v-model="searchValue" size="large" placeholder="输入关键词搜索" class="input-with-select">
<el-input v-model="state.searchValue" size="large" placeholder="输入关键词搜索" class="input-with-select">
<template #append>
<el-button><i class="iconfont icon-search"></i></el-button>
</template>
</el-input>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, watch } from 'vue'
<script lang="ts" setup>
import { reactive, toRefs, watch, defineProps, defineEmits, defineExpose } from 'vue'
import { ElDropdown, ElDropdownItem, ElDropdownMenu } from 'element-plus'
import { useRoute } from 'vue-router'
import api from '@/api'
export default defineComponent({
components: { ElDropdown, ElDropdownItem, ElDropdownMenu },
props: ['type', 'modelValue'],
emits: ['update:modelValue'],
setup(props, context) {
const route = useRoute()
const state: any = reactive({
searchValue: '',
materialCates: [],
currentIndex: 1,
})
type TProps = {
type: string
modelValue: string
}
if (props.type != 'none') {
api.home.getCategories({ type: 1 }).then((list: any) => {
list.unshift({ id: 0, name: '全部' })
state.materialCates = list
const { cate } = route.query
cate && (state.currentIndex = cate)
cate && action('change', state.materialCates[Number(cate)], Number(cate))
})
}
type TEmits = {
(event: 'update:modelValue', data: string): void
(event: 'change', data: TMaterialCatesData): void
}
watch(
() => state.searchValue,
() => {
context.emit('update:modelValue', state.searchValue)
},
)
type TMaterialCatesData = {id: string | number, name: string}
function action(fn: string, type: any, currentIndex: number | string) {
currentIndex && (state.currentIndex = currentIndex)
context.emit(fn, type)
}
return {
...toRefs(state),
action,
}
},
type TState = {
searchValue: string
materialCates: TMaterialCatesData[]
currentIndex: number | string
}
const props = defineProps<TProps>()
const emit = defineEmits<TEmits>()
const route = useRoute()
const state = reactive<TState>({
searchValue: '',
materialCates: [],
currentIndex: 1,
})
if (props.type != 'none') {
api.home.getCategories({ type: 1 }).then((list: any) => {
list.unshift({ id: 0, name: '全部' })
state.materialCates = list
const { cate } = route.query
cate && (state.currentIndex = cate as string)
cate && action('change', state.materialCates[Number(cate)], Number(cate))
})
}
watch(
() => state.searchValue,
() => {
emit('update:modelValue', state.searchValue)
},
)
function action(fn: 'change', type: TMaterialCatesData, currentIndex: number | string) {
currentIndex && (state.currentIndex = currentIndex)
emit(fn, type)
}
defineExpose({
action
})
</script>
<style lang="less" scoped>