xo_user_client/components/diy/modules/custom/data-group-rendering.vue

279 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view :class="'wh-auto pr allSignList-' + propIndex + propKey" :style="'height:' + propDataHeight * propScale + 'px;'">
<view v-for="(item, index) in new_list" :key="index" :data-id="item.id" :data-location-x="item.location.x" :data-location-y="item.location.y" :class="'sign-' + propIndex + propKey + ' main-content ' + get_animation_class(item.com_data)" :style="'left:' + get_percentage_count(item.location.x, item.com_data.data_follow, 'left') + ';top:' + get_percentage_count(item.location.y, item.com_data.data_follow, 'top') + ';width:' + get_percentage_count(item.com_data.com_width, item.com_data.data_follow, 'width', item.com_data.is_width_auto, item.com_data.max_width, item.key) + ';height:' + get_percentage_count(item.com_data.com_height, item.com_data.data_follow, 'height', item.com_data.is_height_auto, item.com_data.max_height, item.key) + ';z-index:' + (new_list.length - 1 > 0 ? (new_list.length - 1) - index : 0)">
<template v-if="item.key == 'text'">
<model-text :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propTitleParams="propShowData.data_name" @url_event="url_event"></model-text>
</template>
<template v-else-if="item.key == 'img'">
<model-image :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propImgParams="propShowData.data_logo" @url_event="url_event"></model-image>
</template>
<template v-else-if="item.key == 'auxiliary-line'">
<model-lines :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId"></model-lines>
</template>
<template v-else-if="item.key == 'icon'">
<model-icon :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-icon>
</template>
<template v-else-if="item.key == 'panel'">
<model-panel :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-panel>
</template>
</view>
</view>
</template>
<script>
import modelText from '@/components/diy/modules/custom/model-text.vue';
import modelLines from '@/components/diy/modules/custom/model-lines.vue';
import modelImage from '@/components/diy/modules/custom/model-image.vue';
import modelIcon from '@/components/diy/modules/custom/model-icon.vue';
import modelPanel from '@/components/diy/modules/custom/model-panel.vue';
import { location_compute, isEmpty } from '@/common/js/common/common.js';
export default {
components: {
modelText,
modelLines,
modelImage,
modelIcon,
modelPanel,
},
props: {
propCustomList: {
type: Array,
default: () => {
return [];
},
required: true,
},
propIndex: {
type: Number,
default: 0,
},
propSourceList: {
type: Object,
default: () => {
return {};
}
},
propDataHeight: {
type: Number,
default: 0,
},
propScale: {
type: Number,
default: 1,
},
propDataIndex: {
type: Number,
default: 1,
},
propDataSplitIndex: {
type: Number,
default: 1,
},
propIsCustom: {
type: Boolean,
default: false,
},
propIsCustomGroup: {
type: Boolean,
default: false
},
propShowData: {
type: Object,
default: () => ({
data_key: 'id',
data_name: 'name'
}),
},
propKey: {
type: [String, Number],
default: '',
},
propCustomGroupFieldId: {
type: String,
default: ''
},
propFieldList: {
type: Array,
default: () => {
return [];
}
},
propConfigLoop: {
type: String,
default: "1"
}
},
data() {
return {
new_list: [],
custom_width: 0,
};
},
watch: {
propKey(val) {
// 初始化
this.init(this.propCustomList);
},
propCustomList(val) {
this.init(val);
}
},
computed: {
get_percentage_count() {
return (num, data_follow, type, is_auto = '0', max_size = 0, key = '') => {
// 检查类型是否为'left'或'top',如果是,则根据跟随数据计算样式
if (['left', 'top'].includes(type)) {
const { id = '', type: follow_type = 'left' } = data_follow || { id: '', type: 'left' };
// 如果id不为空且follow_type与type匹配则返回原始值的字符串表示
if (id !== '' && follow_type === type) {
return `${num}px`;
}
// 如果条件不满足则根据比例缩放num并返回
return `${num * this.propScale}px`;
} else {
// 如果is_auto设置为'1'则根据type和max_size计算自动样式
if (is_auto === '1') {
if (type === 'width' || type === 'height') {
if (typeof max_size === 'number' && max_size >= 0) {
const scaledMaxSize = max_size * this.propScale;
const autoStyle = 'auto;';
const maxSizeStyle = scaledMaxSize > 0 ? ` max-${type}: ${scaledMaxSize}px;` : '';
const whiteSpaceStyle = type === 'width' && scaledMaxSize <= 0 ? ' white-space:nowrap;' : '';
return `${ autoStyle }${ maxSizeStyle }${ whiteSpaceStyle }`;
} else {
return 'auto;';
}
}
} else {
// 微信小程序图片等比缩放对小数点后的内容支持的不是特别的好,需要取向上取整数
if (key == 'img' && ['width', 'height'].includes(type)) {
// 如果is_auto未设置或条件不满足则根据比例缩放num并返回
return `${ Math.round(num * this.propScale) }px`;
} else {
// 如果is_auto未设置或条件不满足则根据比例缩放num并返回
return `${num * this.propScale}px`;
}
}
}
};
},
get_animation_class() {
return (data) => {
const { type = 'none', number = 'infinite' } = data?.animation_style || {};
if (type != 'none') {
return type + (number == 'infinite' ? `-${number}` : '');
} else {
return '';
}
};
}
},
mounted() {
this.init(this.propCustomList);
},
methods: {
async init(val) {
// 如果为空就不进行渲染
if (isEmpty(val)) {
return;
}
await this.get_custom_width();
this.set_new_list(val);
},
get_custom_width() {
// 获取当前容器的宽度
const query = uni.createSelectorQuery().in(this);
query.select('.allSignList-' + this.propIndex + this.propKey)
.boundingClientRect((res) => {
if (res) {
this.setData({
custom_width: res.width,
});
}
})
.exec();
},
async set_new_list(val) {
// 第一次渲染先渲染全部数据
this.setData({
new_list: val
});
// 判断是否有跟随的数据
const follow_list = val.filter(item => item.com_data.data_follow && item.com_data?.data_follow?.id !== '');
if (follow_list.length > 0) {
// 等待页面渲染完成之后再获取内容
await this.$nextTick();
// 第二次如果有跟随数据,更新对应数据的内容, 如果有超出容器范围的数据,限制其超出容器范围
const query = uni.createSelectorQuery().in(this);
query.selectAll('.sign-' + this.propIndex + this.propKey)
.boundingClientRect((rect) => {
if (rect) {
// 将返回的内容转成map对象方便快速查找节省性能
const idMap = new Map(rect.map(item => [item.dataset.id, item]));
// 历史数据拷贝,方便后续操作避免每次都更新数据,统一重新渲染
const val = JSON.parse(JSON.stringify(this.new_list));
val.forEach((item1) => {
const { data_follow } = item1.com_data;
const targetItem = idMap.get(data_follow?.id);
if (targetItem) {
const text_item = item1.key == 'text' ? idMap.get((item1?.id || '')+ '') : undefined;
if (data_follow?.type === 'left') {
// 更新位置信息
const location_x = this.updateLocation(targetItem, data_follow, this.propScale, true);
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
let item_width = item1.com_data.com_width;
// 如果是宽度自适应,需要重新判断一下处理逻辑
if (item1.com_data?.is_width_auto === '1' && text_item) {
item_width = text_item.width;
}
// 根据容器信息更新位置信息
item1.location.x = location_compute(item_width, location_x, this.custom_width);
} else if (data_follow?.type === 'top') {
// 更新位置信息
const location_y = this.updateLocation(targetItem, data_follow, this.propScale, false);
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
let item_height = item1.com_data.com_height;
// 如果是高度自适应,需要重新判断一下处理逻辑
if (item1.com_data?.is_height_auto === '1' && text_item) {
item_height = text_item.height;
}
// 根据容器信息更新位置信息
item1.location.y = location_compute(item_height, location_y, this.propDataHeight * this.propScale);
}
}
});
this.setData({
new_list: val
});
}
})
.exec();
}
},
updateLocation(targetItem, data_follow, scale, isX) {
try {
const locationValueStr = targetItem.dataset[`location${isX ? 'X' : 'Y'}`];
if (locationValueStr == null) {
return;
}
const locationValue = parseFloat(locationValueStr);
if (isNaN(locationValue) || scale <= 0 || (isX ? targetItem.width < 0 : targetItem.height < 0)) return;
return ((locationValue + (data_follow?.spacing || 0)) * scale) + (isX ? targetItem.width : targetItem.height);
} catch (error) {
console.error(`Error updating location ${isX ? 'X' : 'Y'}:`, error);
}
},
url_event(e) {
this.$emit('url_event', e, this.propDataIndex, this.propDataSplitIndex);
}
},
};
</script>
<style lang="scss" scoped>
.main-content {
position: absolute;
overflow: hidden;
}
</style>