feat: 添加图片选择组件

master
绝弹 2023-10-10 22:48:11 +08:00
parent 2bc4ac1d34
commit 2076a87f19
22 changed files with 444 additions and 128 deletions

View File

@ -7,9 +7,7 @@
<a-tooltip content="固定水平方向">
<i
class="cursor-pointer text-gray-400 hover:text-gray-700"
:class="
data.xFixed ? 'icon-park-outline-lock text-gray-900' : 'icon-park-outline-unlock text-gray-400'
"
:class="data.xFixed ? 'icon-park-outline-lock text-gray-900' : 'icon-park-outline-unlock text-gray-400'"
@click="data.xFixed = !data.xFixed"
></i>
</a-tooltip>
@ -22,9 +20,7 @@
<a-tooltip content="固定垂直方向">
<i
class="cursor-pointer text-gray-400 hover:text-gray-700"
:class="
data.yFixed ? 'icon-park-outline-lock text-gray-900' : 'icon-park-outline-unlock text-gray-400'
"
:class="data.yFixed ? 'icon-park-outline-lock text-gray-900' : 'icon-park-outline-unlock text-gray-400'"
@click="data.yFixed = !data.yFixed"
></i>
</a-tooltip>
@ -43,11 +39,7 @@
</div>
<a-form-item label="背景图片">
<a-input v-model="data.bgImage" class="group w-full" allow-clear placeholder="暂无">
<template #prefix>
<a-link class="!text-xs">选择</a-link>
</template>
</a-input>
<input-image v-model="data.bgImage"></input-image>
</a-form-item>
<a-form-item label="背景颜色">
@ -62,6 +54,7 @@
<script setup lang="ts">
import { PropType } from "vue";
import InputImage from "../../components/InputImage.vue";
defineProps({
data: {
@ -70,5 +63,3 @@ defineProps({
},
});
</script>
<style scoped></style>

View File

@ -1,16 +1,189 @@
<template>
<a-modal title="选择图片" v-model:visible="visible" title-align="start" :closable="false">
<div class="flex flex-wrap gap-4">
<div v-for="item in images" :key="item" class="w-24 h-24 bg-gray-200 flex items-center justify-center">
<img :src="item" class="w-full h-full object-cover" />
<a-modal
v-model:visible="innerVisible"
title="选择图片"
title-align="start"
:width="1080"
:closable="false"
:mask-closable="false"
:ok-button-props="{ disabled: !seleted.length }"
>
<div class="w-full flex items-center justify-between gap-4">
<div>
<a-button type="outline" class="!text-gray-700 !border-gray-300">
<template #icon>
<i class="icon-park-outline-upload"></i>
</template>
上传
</a-button>
</div>
<div>
<a-input-search
:disabled="loading"
class="!w-48 mr-2"
placeholder="请输入素材名称"
@search="loadData"
></a-input-search>
</div>
</div>
<a-spin :loading="loading" :dot="true" tip="正在加载中,请稍等..." class="h-[450px] w-full">
<div class="h-[450px] grid grid-cols-5 grid-rows-2 items-start justify-between gap-4 mt-2">
<div
v-for="item in images"
:key="item.title"
:class="{
selected: selectedKeys.includes(item.id),
}"
class="p-2 border border-transparent rounded"
@click="onSelectedImage(item)"
>
<div class="w-full bg-gray-50 flex items-center justify-center">
<img :src="item.url" class="w-full aspect-video object-cover rounded hover:opacity-80" />
</div>
<div class="mt-2 flex items-center gap-2">
<div class="flex-1 truncate">
{{ item.title }}
</div>
<div class="text-xs text-gray-400">1280 * 800</div>
</div>
</div>
</div>
<div class="mt-2 flex justify-end">
<a-pagination
v-model:current="pagination.page"
v-model:page-size="pagination.size"
:total="pagination.total"
:disabled="loading"
@change="loadData"
@page-size-change="loadData"
></a-pagination>
</div>
</a-spin>
<template #footer>
<div class="flex items-center justify-between gap-4">
<div>已选: {{ seleted.length }} </div>
<div>
<a-button class="mr-2" @click="onClose"></a-button>
<a-button type="primary" @click="onBeforeOk" :disabled="!seleted.length">确定</a-button>
</div>
</div>
</template>
</a-modal>
</template>
<script setup lang="ts">
const visible = ref(false);
const images = ref([]);
import { mockLoad } from "./mock";
const props = defineProps({
modelValue: {
type: String,
default: "",
},
visible: {
type: Boolean,
default: false,
},
multiple: {
type: Boolean,
default: false,
},
load: {
type: Function,
default: mockLoad,
},
});
const loadData = async () => {
const { page, size } = pagination.value;
const params = { ...search.value, page, size };
try {
loading.value = true;
const { data, total } = await props.load(params);
images.value = data;
pagination.value.total = total;
} finally {
loading.value = false;
}
};
const pagination = ref({ page: 1, size: 15, total: 0 });
const search = ref({ name: "" });
const loading = ref(false);
const images = ref<any[]>([]);
const seleted = ref<any[]>([]);
const selectedKeys = computed(() => seleted.value.map((item) => item.id));
const onBeforeOk = () => {
emit("update:modelValue", seleted.value[0]?.url);
onClose();
};
const onClose = () => {
seleted.value = [];
images.value = [];
pagination.value.page = 1;
pagination.value.total = 0;
search.value.name = "";
innerVisible.value = false;
};
const onSelectedImage = (image: any) => {
if (selectedKeys.value.includes(image.id)) {
seleted.value = seleted.value.filter((item) => item.id !== image.id);
} else {
if (!props.multiple) {
seleted.value = [image];
return;
}
seleted.value.push(image);
}
};
watch(
() => props.visible,
async (value) => {
if (!value) return;
loadData();
}
);
const emit = defineEmits(["update:modelValue", "update:visible"]);
const innerVisible = computed({
get: () => props.visible,
set: (value) => emit("update:visible", value),
});
</script>
<style scoped></style>
<style scoped>
.selected {
position: relative;
border-color: rgb(var(--primary-6));
background-color: rgb(var(--primary-1));
cursor: pointer;
}
.selected:after {
content: "";
position: absolute;
bottom: 0px;
right: 0px;
width: 0;
height: 0;
border-bottom: 20px solid #09f;
border-left: 20px solid transparent;
}
.selected:before {
content: "";
position: absolute;
bottom: 5px;
right: 1px;
width: 10px;
height: 5px;
border: 2px solid white;
border-top: none;
border-right: none;
transform: rotate(-55deg);
z-index: 2;
}
</style>

View File

@ -0,0 +1,26 @@
<template>
<a-input v-model="model">
<template #prefix>
<color-picker v-model="model"></color-picker>
</template>
</a-input>
</template>
<script setup lang="ts">
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:modelValue"]);
const model = computed({
get: () => props.modelValue,
set: (value) => emit("update:modelValue", value),
});
</script>
<style scoped></style>

View File

@ -0,0 +1,29 @@
<template>
<a-input v-model="model" class="group w-full" allow-clear placeholder="暂无">
<template #prefix>
<a-link @click="visible = true">选择</a-link>
</template>
</a-input>
<image-picker v-model="model" v-model:visible="visible"></image-picker>
</template>
<script setup lang="ts">
import ImagePicker from './ImagePicker.vue';
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:modelValue"]);
const visible = ref(false);
const model = computed({
get: () => props.modelValue,
set: (value) => emit("update:modelValue", value),
});
</script>
<style scoped></style>

View File

@ -0,0 +1,29 @@
const sleep = (time: number) => {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, time);
});
};
interface MockParams {
page: number;
size: number;
}
export const mockLoad = async (params: MockParams) => {
const { page, size } = params;
await sleep(1000);
const counts = Array(15).fill(9);
const data = counts.map((v, i) => {
return {
id: (page - 1) * size + i,
title: "图片1",
url: `https://source.unsplash.com/random?sig=${(page - 1) * size + i}`,
};
});
return {
data,
total: 100,
};
};

View File

@ -11,7 +11,7 @@ export interface Block<T = any> {
bgColor?: string;
data: T;
meta: Record<string, any>;
actived: false,
actived: boolean,
resizable: boolean,
draggable: boolean,
}

View File

@ -1,11 +1,13 @@
export interface Container {
id: number | string;
x: number;
y: number;
zoom: number;
title: string;
description?: string;
description: string;
width: number;
height: number;
bgImage?: string;
bgColor?: string;
zoom: number;
bgImage: string;
bgColor: string;
}

View File

@ -3,12 +3,13 @@ import { Block } from "./block";
import { Container } from "./container";
export interface Context {
current: {
block: Block;
};
current: Ref<{
block: Block | null;
}>;
blocks: Ref<Block[]>;
container: Ref<Container>;
setCurrentBlock: (block: Block) => void;
setContainerOrigin: () => void;
}
export const ContextKey = Symbol('ContextKey') as InjectionKey<Context>;

View File

@ -20,13 +20,13 @@
</template>
<script setup lang="ts">
import { ContextKey } from "./config";
import { Block, Container, ContextKey } from "./config";
import PanelHeader from "./panel-header/index.vue";
import PanelLeft from "./panel-left/index.vue";
import PanelMain from "./panel-main/index.vue";
import PanelRight from "./panel-right/index.vue";
const blocks = ref<Block>([]);
const blocks = ref<Block[]>([]);
const current = ref({
block: null as Block | null,
@ -36,30 +36,40 @@ const container = ref<Container>({
id: 11,
title: "国庆节喜庆版式设计",
description: "适用于国庆节1日-7日间上午9:00-10:00播出的版式设计",
x: 0,
y: 0,
zoom: 0.7,
width: 1920,
height: 1080,
bgImage: "",
bgColor: "#ffffff",
zoom: 1,
});
const setCurrentBlock = (block: Block | null) => {
for (const block of blocks.value) {
block.active = false;
block.actived = false;
}
if (!block) {
current.value.block = null;
return;
}
block.active = true;
block.actived = true;
current.value.block = block;
};
//
const setContainerOrigin = () => {
container.value.x = 0;
container.value.y = 0;
container.value.zoom = 0.7;
};
provide(ContextKey, {
current,
container,
blocks,
setCurrentBlock,
setContainerOrigin,
});
</script>

View File

@ -1,7 +1,7 @@
<template>
<div class="h-full grid grid-cols-[auto_1fr]" :style="{ width: !collapsed ? '248px' : undefined }">
<div class="h-full grid grid-rows-[1fr_auto] border-r border-slate-200">
<a-menu :collapsed="true">
<a-menu :collapsed="true" :default-selected-keys="['0_0']">
<a-menu-item key="0_0">
<template #icon>
<i class="icon-park-outline-all-application"></i>
@ -57,7 +57,7 @@
<script setup lang="ts">
const collapsed = ref(false);
const onDragStart = (e: Event) => {
const onDragStart = (e: DragEvent) => {
console.log('start');
e.dataTransfer?.setData("type", (e.target as HTMLElement).dataset.type!);
}

View File

@ -6,11 +6,11 @@
:h="data.h"
:parentW="container.width"
:parentH="container.height"
:parentScaleX="container.zoom / 100"
:parentScaleY="container.zoom / 100"
:parentScaleX="container.zoom"
:parentScaleY="container.zoom"
:parentLimitation="true"
:preventActiveBehavior="!data.draggable"
:isActive="data.active"
:isActive="data.actived"
:isResizable="data.resizable"
:style="blockStyle"
@dragging="onItemDragOrResize"
@ -23,9 +23,9 @@
<script setup lang="ts">
import { PropType } from "vue";
import { Block, Container, ContextKey } from "../../config";
import { BlockerMap } from "../../items";
import { BlockerMap } from "../../blocks";
import DragResizer from "../../components/DragResizer.vue";
import { Block, Container, ContextKey } from "../../config";
const props = defineProps({
data: {
@ -38,7 +38,7 @@ const props = defineProps({
},
});
const { setCurrentBlock } = inject(ContextKey);
const { setCurrentBlock } = inject(ContextKey)!;
const blockStyle = computed(() => {
const { bgColor, bgImage } = props.data;

View File

@ -3,43 +3,33 @@
<div class="flex-1">
<div class="group">
<span class="text-gray-400">描述: </span>
<span v-if="!descEditing">
{{ container.description }}
<i
class="!hidden !group-hover:inline-block icon-park-outline-edit text-gray-400 hover:text-gray-700 ml-1 cursor-pointer"
@click="onDescEdit"
></i>
</span>
<span v-else class="inline-flex items-center">
<a-input size="small" v-model="descContent" class="!w-96"></a-input>
<a-button type="text" size="small" @click="onDescEdited" class="ml-2">
<template #icon>
<i class="icon-park-outline-check"></i>
</template>
</a-button>
<a-button type="text" size="small" class="!text-gray-500" @click="descEditing = false">
<template #icon>
<i class="icon-park-outline-close"></i>
</template>
</a-button>
</span>
<ani-texter v-model="container.description"></ani-texter>
</div>
</div>
<div class="flex items-center">
<span class="text-gray-400 text-xs mr-2">
<span class="text-gray-400 text-xs mr-3">
坐标
<span class="text-gray-700">{{ Math.floor(container.x) }} , {{ Math.floor(container.y) }} </span>
</span>
<span class="text-gray-400 text-xs mr-3">
尺寸
<span class="text-gray-700"> {{ container.width }} * {{ container.height }} </span>
<span class="text-gray-700">{{ container.width }} * {{ container.height }} </span>
</span>
<span class="text-gray-400 text-xs mr-2">
比例
<span class="text-gray-700">
{{ parseInt(container.zoom * 100) }}%
</span>
<span class="inline-block w-8 text-gray-700">{{ Math.floor(container.zoom * 100) }}% </span>
</span>
<span class="text-gray-400 text-xs mr-2">
组件
<span class="text-gray-700">{{ 2 }} </span>
<span class="inline-block w-6 text-gray-700">{{ blocks.length }} </span>
</span>
<a-tooltip content="自适应比例" position="bottom">
<a-button type="text" @click="setContainerOrigin">
<template #icon>
<i class="icon-park-outline-equal-ratio text-base !text-gray-600"></i>
</template>
</a-button>
</a-tooltip>
<a-tooltip content="预览" position="bottom">
<a-button type="text">
<template #icon>
@ -48,20 +38,24 @@
</a-button>
</a-tooltip>
<a-popover position="br" trigger="click">
<a-button type="text">
<template #icon>
<i class="icon-park-outline-config text-base !text-gray-600"></i>
</template>
</a-button>
<a-tooltip content="设置" position="bottom">
<a-button type="text">
<template #icon>
<i class="icon-park-outline-config text-base !text-gray-600"></i>
</template>
</a-button>
</a-tooltip>
<template #content>
<span>
背景图片:
<a-link>选择</a-link>
</span>
<span class="inline-flex items-center">
背景颜色
<color-picker></color-picker>
</span>
<a-form :model="{}" layout="vertical">
<div class="muti-form-item">
<a-form-item label="背景图片">
<input-image v-model="container.bgImage"></input-image>
</a-form-item>
<a-form-item label="背景颜色">
<input-color v-model="container.bgColor"></input-color>
</a-form-item>
</div>
</a-form>
</template>
</a-popover>
</div>
@ -69,25 +63,12 @@
</template>
<script setup lang="ts">
const props = defineProps({
container: {
type: Object as PropType<any>,
required: true,
},
});
import InputColor from "../../components/InputColor.vue";
import InputImage from "../../components/InputImage.vue";
import { ContextKey } from "../../config";
import AniTexter from "./texter.vue";
const descEditing = ref(false);
const descContent = ref("");
const onDescEdited = () => {
props.container.description = descContent.value;
descEditing.value = false;
};
const onDescEdit = () => {
descContent.value = props.container.description;
descEditing.value = true;
};
const { container, blocks, setContainerOrigin } = inject(ContextKey)!;
</script>
<style scoped></style>

View File

@ -0,0 +1,47 @@
<template>
<span v-if="!descEditing">
{{ modelValue }}
<i
class="!hidden !group-hover:inline-block icon-park-outline-edit text-gray-400 hover:text-gray-700 ml-1 cursor-pointer"
@click="onDescEdit"
></i>
</span>
<span v-else class="inline-flex items-center">
<a-input size="small" v-model="descContent" class="!w-96"></a-input>
<a-button type="text" size="small" @click="onDescEdited" class="ml-2">
<template #icon>
<i class="icon-park-outline-check"></i>
</template>
</a-button>
<a-button type="text" size="small" class="!text-gray-500" @click="descEditing = false">
<template #icon>
<i class="icon-park-outline-close"></i>
</template>
</a-button>
</span>
</template>
<script setup lang="ts">
const props = defineProps({
modelValue: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:modelValue"]);
const descEditing = ref(false);
const descContent = ref("");
const onDescEdited = () => {
emit("update:modelValue", descContent.value);
descEditing.value = false;
};
const onDescEdit = () => {
descContent.value = props.modelValue;
descEditing.value = true;
};
</script>
<style scoped></style>

View File

@ -22,10 +22,11 @@
</template>
<script setup lang="ts">
import ColorPicker from "../components/ColorPicker.vue";
import { ContextKey } from "../config";
import AniBlock from "./components/block.vue";
import AniHeader from "./components/header.vue";
import { Block, ContextKey, Container } from "../config";
const { blocks, container } = inject(ContextKey)!;
const isStart = ref(false);
const position = ref({
@ -37,19 +38,19 @@ const position = ref({
mouseY: 0,
});
const onMouseDown = (e: Event) => {
const onMouseDown = (e: MouseEvent) => {
isStart.value = true;
position.value.startX = e.offsetX;
position.value.startY = e.offsetY;
};
const onMouseMove = (e: Event) => {
const onMouseMove = (e: MouseEvent) => {
if (!isStart.value) {
return;
}
const scale = container.value.zoom;
position.value.x += (e.offsetX - position.value.startX) * scale;
position.value.y += (e.offsetY - position.value.startY) * scale;
container.value.x += (e.offsetX - position.value.startX) * scale;
container.value.y += (e.offsetY - position.value.startY) * scale;
};
const onMouseUp = () => {
@ -64,11 +65,8 @@ onUnmounted(() => {
window.removeEventListener("mouseup", onMouseUp);
});
const { blocks, container } = inject(ContextKey);
const containerStyle = computed(() => {
const { width, height, bgColor, bgImage, zoom } = container.value;
const { x, y } = position.value;
const { width, height, bgColor, bgImage, zoom, x, y } = container.value;
return {
position: "absolute",
width: `${width}px`,
@ -76,13 +74,13 @@ const containerStyle = computed(() => {
backgroundColor: bgColor,
backgroundImage: bgImage ? `url(${bgImage})` : undefined,
backgroundSize: "100% 100%",
// transform: `translate3d(${x}px, ${y}px, 0) scale(${zoom})`,
transform: `matrix(${zoom}, 0, 0, ${zoom}, ${x}, ${y})`,
transform: `translate3d(${x}px, ${y}px, 0) scale(${zoom})`,
// transform: `matrix(${zoom}, 0, 0, ${zoom}, ${x}, ${y})`,
// transformOrigin: "0 0",
};
} as any;
});
const onDragDrop = (e: Event) => {
const onDragDrop = (e: DragEvent) => {
e.preventDefault();
e.stopPropagation();
@ -92,8 +90,7 @@ const onDragDrop = (e: Event) => {
}
blocks.value.push({
x: 0,
y: 0,
id: "0",
w: 200,
h: 100,
bgColor: "#0099ff",
@ -104,6 +101,9 @@ const onDragDrop = (e: Event) => {
type,
x: e.offsetX,
y: e.offsetY,
data: {},
meta: {},
actived: false,
});
};
@ -111,14 +111,12 @@ const onMouseWheel = (e: WheelEvent) => {
e.preventDefault();
const prezoom = container.value.zoom;
let zoom = prezoom;
if (e.wheelDelta > 0) {
console.log("放大");
if (e.deltaY > 0) {
zoom += 0.1;
if (zoom > 10) {
return;
}
} else {
console.log("缩小");
zoom -= 0.1;
if (zoom < 0.1) {
return;

View File

@ -17,12 +17,11 @@
</template>
<script setup lang="ts">
import BlockAttr from "./block-attr.vue";
import TextAttr from "./text-attr.vue";
import { BlockerMap } from "../blocks";
import { ContextKey } from "../config";
import BlockerMap from "../items";
import TextAttr from "./text-attr.vue";
const { current } = inject(ContextKey);
const { current } = inject(ContextKey)!;
const item = ref<any>({
x: 0,

View File

@ -0,0 +1,13 @@
<template>
<div>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

View File

@ -7,25 +7,34 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
AAvatar: typeof import('@arco-design/web-vue')['Avatar']
AButton: typeof import('@arco-design/web-vue')['Button']
ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
ADivider: typeof import('@arco-design/web-vue')['Divider']
ADoption: typeof import('@arco-design/web-vue')['Doption']
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
ADropdown: typeof import('@arco-design/web-vue')['Dropdown']
ADropdownButton: typeof import('@arco-design/web-vue')['DropdownButton']
AForm: typeof import('@arco-design/web-vue')['Form']
AFormItem: typeof import('@arco-design/web-vue')['FormItem']
AInput: typeof import('@arco-design/web-vue')['Input']
AInputNumber: typeof import('@arco-design/web-vue')['InputNumber']
AInputPassword: typeof import('@arco-design/web-vue')['InputPassword']
AInputSearch: typeof import('@arco-design/web-vue')['InputSearch']
ALayout: typeof import('@arco-design/web-vue')['Layout']
ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent']
ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader']
ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider']
ALink: typeof import('@arco-design/web-vue')['Link']
AMenu: typeof import('@arco-design/web-vue')['Menu']
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
AMenuItemGroup: typeof import('@arco-design/web-vue')['MenuItemGroup']
AModal: typeof import('@arco-design/web-vue')['Modal']
APagination: typeof import('@arco-design/web-vue')['Pagination']
APopover: typeof import('@arco-design/web-vue')['Popover']
ARadio: typeof import('@arco-design/web-vue')['Radio']
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
AScrollbar: typeof import('@arco-design/web-vue')['Scrollbar']
ASelect: typeof import('@arco-design/web-vue')['Select']
ASpace: typeof import('@arco-design/web-vue')['Space']
ASpin: typeof import('@arco-design/web-vue')['Spin']
ATag: typeof import('@arco-design/web-vue')['Tag']
ATextarea: typeof import('@arco-design/web-vue')['Textarea']
ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
@ -38,16 +47,20 @@ declare module '@vue/runtime-core' {
Editor: typeof import('./../components/editor/index.vue')['default']
Header: typeof import('./../components/editor/panel-main/components/header.vue')['default']
ImagePicker: typeof import('./../components/editor/components/ImagePicker.vue')['default']
Option: typeof import('./../components/editor/items/text/option.vue')['default']
InputColor: typeof import('./../components/editor/components/InputColor.vue')['default']
InputImage: typeof import('./../components/editor/components/InputImage.vue')['default']
Option: typeof import('./../components/editor/blocks/text/option.vue')['default']
Page403: typeof import('./../components/error/page-403.vue')['default']
PanelHeader: typeof import('./../components/editor/panel-header/index.vue')['default']
PanelLeft: typeof import('./../components/editor/panel-left/index.vue')['default']
PanelMain: typeof import('./../components/editor/panel-main/index.vue')['default']
PanelRight: typeof import('./../components/editor/panel-right/index.vue')['default']
Render: typeof import('./../components/editor/items/text/render.vue')['default']
Preview: typeof import('./../components/editor/preview/index.vue')['default']
Render: typeof import('./../components/editor/blocks/text/render.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
TextAttr: typeof import('./../components/editor/panel-right/text-attr.vue')['default']
Texter: typeof import('./../components/editor/panel-main/components/texter.vue')['default']
Toast: typeof import('./../components/toast/toast.vue')['default']
}
}

View File

@ -8,9 +8,9 @@ import { ArcoResolver } from "unplugin-vue-components/resolvers";
import AutoComponent from "unplugin-vue-components/vite";
import { defineConfig, loadEnv } from "vite";
import Page from "vite-plugin-pages";
import plugin from "./scripts/vite/plugin";
import { arcoToUnoColor } from "./scripts/vite/color";
import fileIcon from "./scripts/vite/icon-file.json";
import plugin from "./scripts/vite/plugin";
/**
* vite
@ -51,7 +51,11 @@ export default defineConfig(({ mode }) => {
* Vue 3
* @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue
*/
Vue({}),
Vue({
script: {
defineModel: true
}
}),
/**
* Vue 3 JSX