Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7c9e233

Browse files
committed
feat: 图片懒加载
1 parent 8af03e3 commit 7c9e233

File tree

9 files changed

+198
-25
lines changed

9 files changed

+198
-25
lines changed

‎package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
},
1111
"dependencies": {
1212
"clipboard": "^2.0.11",
13-
"uuid": "^9.0.0",
14-
"vue": "^3.2.47"
13+
"vue": "^3.2.47",
14+
"vue3-lazy": "^1.0.0-alpha.1"
1515
},
1616
"devDependencies": {
1717
"@types/uuid": "^9.0.1",

‎src/DrawPanel.vue‎

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,53 @@
22
import { reactive, ref, onMounted } from 'vue';
33
import { Message, MessageStatus } from './interfaces/message'
44
import MessageItem from './Message.vue'
5-
import * as uuid from 'uuid'
65
import { getMessagesAPI, createMessageAPI, upscaleMessageAPI } from './api/midjourney'
6+
import { sendMessage, createWebsocket } from './utils/websocket'
77
8+
const ws = createWebsocket({
9+
onMessage(data) {
10+
// console.log('message event: ', event)
11+
console.log('message event: ', data)
12+
},
13+
onOnLine(data) {
14+
console.log('online data: ', data)
15+
},
16+
onTaskUpdate(data: Message) {
17+
console.log('taskupdate data: ', data)
18+
const { id } = data
19+
findOneAndUpdate(id, data)
20+
setTimeout(() => {
21+
scrollToBottom()
22+
}, 32)
23+
}
24+
})
825
const contentWrap = ref<HTMLDivElement>()
926
const data = reactive<{
1027
messages: Message[],
11-
prompt: string
28+
prompt: string,
29+
pageNum: number,
30+
pageSize: number,
31+
loading: boolean,
32+
loaded: boolean
1233
}>({
1334
prompt: '',
14-
messages: []
35+
messages: [],
36+
pageNum: 1,
37+
pageSize: 5,
38+
loading: false,
39+
loaded: false
1540
})
1641
42+
const findOneAndUpdate = (id: number, msgData: Partial<Message>) => {
43+
const index = data.messages.findIndex((e) => e.id === id)
44+
if (index > -1) {
45+
const target = data.messages[index]
46+
Object.keys(msgData).forEach((key) => {
47+
target[key] = msgData[key]
48+
})
49+
}
50+
}
51+
1752
const onClickSend = () => {
1853
sendPrompt()
1954
}
@@ -24,10 +59,16 @@ const onKeyDown = (event: Event) => {
2459
sendPrompt()
2560
}
2661
27-
const getList = () => {
28-
getMessagesAPI().then((resData) => {
29-
data.messages = resData as any;
62+
const getList = (params: any) => {
63+
if (data.loading || data.loaded) return
64+
getMessagesAPI(params).then((resData) => {
65+
// data.messages = resData as any;
66+
resData = resData || [] as any
67+
data.messages = [...resData as any, ...data.messages];
68+
data.loaded = !resData || !(resData as any).length
3069
scrollToBottom()
70+
}).finally(() => {
71+
data.loading = false
3172
})
3273
}
3374
@@ -40,7 +81,8 @@ const sendPrompt = async () => {
4081
prompt: data.prompt,
4182
createTime: Date.now(),
4283
uri: "",
43-
id: msgId
84+
id: msgId,
85+
status: MessageStatus.INIT
4486
}
4587
4688
data.messages.push(msgObj)
@@ -66,7 +108,7 @@ const onUpscale = async (msg: Message) => {
66108
id: newId,
67109
prompt: data.prompt,
68110
index,
69-
status: MessageStatus.START,
111+
status: MessageStatus.INIT,
70112
}
71113
data.messages.push(newMsg)
72114
scrollToBottom()
@@ -80,9 +122,24 @@ const scrollToBottom = () => {
80122
})
81123
}
82124
125+
const onContentWrapScroll = (event: Event) => {
126+
if (data.loading || data.loaded) return
127+
const el = contentWrap.value
128+
if (el.scrollTop <= 100) {
129+
getList({ pageNum: ++data.pageNum, pageSize: data.pageSize })
130+
}
131+
}
132+
83133
onMounted(() => {
134+
getList({ pageNum: 1, pageSize: data.pageSize })
84135
scrollToBottom()
85-
getList()
136+
setTimeout(() => {
137+
contentWrap.value.addEventListener('scroll', onContentWrapScroll)
138+
})
139+
140+
return () => {
141+
contentWrap.value.removeEventListener('scroll', onContentWrapScroll)
142+
}
86143
})
87144
88145
</script>

‎src/Message.vue‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { Message, MessageStatus } from './interfaces/message';
33
import { copyString } from './utils/clipboard';
44
import Tag from './components/Tag.vue';
5+
import Image from './components/Image.vue';
56
67
const props = defineProps({
78
message: {
@@ -36,6 +37,8 @@ const getMessageStatus = (status: number) => {
3637
return '已完成'
3738
case MessageStatus.TIMEOUT:
3839
return '已超时'
40+
default:
41+
return '排队中'
3942
}
4043
}
4144
</script>
@@ -51,13 +54,7 @@ const getMessageStatus = (status: number) => {
5154
</div>
5255
<div class="text-sm text-slate-300 pt-1">状态:{{ getMessageStatus(message.status) }}</div>
5356
<div class="text-sm text-slate-300">时间:{{ message?.createTime ? getTimeStr(message?.createTime) : '2023年6月2日 下午6:06:32' }}</div>
54-
<div v-if="!message?.uri" class="flex flex-col items-center mt-2 p-4 bg-[#999] w-[140px] h-[140px] rounded-lg justify-center">
55-
<img class="block w-[50px]" src="/src/assets/image.png" alt="">
56-
<p class="pt-4 text-sm">正在排队生成中</p>
57-
</div>
58-
<div v-else class="flex-col w-full mt-2">
59-
<img class="block" :src="message.uri" alt="">
60-
</div>
57+
<Image loadText="排队生成中" :url="message.uri" />
6158
<!-- upscale area -->
6259
<div v-if="message?.status == MessageStatus.DONE && !message.index">
6360
<Tag text="U1" @click="onClickUV(1)" />

‎src/assets/icon_loading.png‎

12.9 KB
Loading[フレーム]

‎src/components/Image.vue‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<script setup lang="ts">
2+
import { reactive } from 'vue';
3+
4+
defineProps({
5+
url: {
6+
type: String
7+
},
8+
width: {
9+
type: [String, Number],
10+
default: '100%'
11+
},
12+
loadText: {
13+
type: String,
14+
default: "加载中"
15+
},
16+
errorText: String,
17+
})
18+
19+
const data = reactive({
20+
loading: false,
21+
loaded: false,
22+
loadError: false
23+
})
24+
25+
const onLoadStart = (event: Event) => {
26+
console.log('load start: ', event)
27+
data.loading = true
28+
}
29+
const onLoadError = (event: Event) => {
30+
console.log('load eroor: ', event)
31+
data.loadError = true
32+
}
33+
const onLoad = () => {
34+
data.loading = false
35+
data.loaded = true
36+
}
37+
</script>
38+
39+
<template>
40+
<img v-if="url" v-lazy="url" class="my-1 w-[100%]" loading="lazy" alt="" @loadstart="onLoadStart" @error="onLoadError" @load="onLoad">
41+
</template>

‎src/interfaces/message.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export interface Message {
2-
id: string
2+
id: number
33
prompt: string
44
done?: boolean
55
uri?: string

‎src/main.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { createApp } from 'vue'
22
import './styles'
33
import App from './App.vue'
4+
import LazyPlugin from 'vue3-lazy'
5+
// import LoadingImage from '/src/assets/image.png'
6+
import LoadingImage from '/src/assets/icon_loading.png'
47

5-
createApp(App).mount('#app')
8+
createApp(App)
9+
.use(LazyPlugin, {
10+
loading: LoadingImage,
11+
error: LoadingImage,
12+
})
13+
.mount('#app')

‎src/utils/websocket.ts‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
3+
interface CreateWsOptions {
4+
onOpen?: (event: Event) => void;
5+
onError?: (event: Event) => void;
6+
onMessage?: (data?: any) => void;
7+
onOnLine?: (data?: any) => void;
8+
onTaskUpdate?: (data?: any) => void;
9+
onClose?: (event: CloseEvent) => void;
10+
}
11+
12+
let wsInstance: WebSocket | null = null;
13+
14+
enum EventType {
15+
MESSAGE = 'message',
16+
ONLINE = 'online',
17+
TASK_UPDATE = 'task_update'
18+
}
19+
20+
export const createWebsocket = (ops?: CreateWsOptions) => {
21+
if (wsInstance) {
22+
return wsInstance;
23+
}
24+
25+
const dispatchEventData = (type: EventType, data: any) => {
26+
switch (type) {
27+
case EventType.MESSAGE:
28+
ops?.onMessage?.(data);
29+
break
30+
case EventType.ONLINE:
31+
ops?.onOnLine?.(data);
32+
break
33+
case EventType.TASK_UPDATE:
34+
ops?.onTaskUpdate?.(data);
35+
break
36+
}
37+
}
38+
39+
const ws = wsInstance = new WebSocket(`ws://43.153.50.34:3333`)
40+
// const ws = wsInstance = new WebSocket(`ws://localhost:3333`);
41+
ws.addEventListener('open', (event) => {
42+
ws.send(JSON.stringify({
43+
event: 'init'
44+
}))
45+
ops?.onOpen?.(event)
46+
});
47+
ws.addEventListener('error', ops?.onError);
48+
ws.addEventListener('message', (event: MessageEvent) => {
49+
let data
50+
try {
51+
data = JSON.parse(event.data)
52+
const { event: type, data: eventData } = data
53+
dispatchEventData(type, eventData)
54+
} catch (error) {
55+
console.log(error)
56+
}
57+
});
58+
ws.addEventListener('close', ops?.onClose);
59+
return ws;
60+
}
61+
62+
export const sendMessage = (data: any) => {
63+
if (!wsInstance) {
64+
throw new Error('ws instance is not exist!')
65+
}
66+
wsInstance.send(JSON.stringify({
67+
type: 'message',
68+
data
69+
}))
70+
}

‎yarn.lock‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,11 +1054,6 @@ util-deprecate@^1.0.2:
10541054
resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
10551055
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
10561056

1057-
uuid@^9.0.0:
1058-
version "9.0.0"
1059-
resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
1060-
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
1061-
10621057
vite@^4.3.9:
10631058
version "4.3.9"
10641059
resolved "https://registry.npmmirror.com/vite/-/vite-4.3.9.tgz#db896200c0b1aa13b37cdc35c9e99ee2fdd5f96d"
@@ -1087,6 +1082,11 @@ vue-tsc@^1.4.2:
10871082
"@volar/vue-typescript" "1.6.5"
10881083
semver "^7.3.8"
10891084

1085+
vue3-lazy@^1.0.0-alpha.1:
1086+
version "1.0.0-alpha.1"
1087+
resolved "https://registry.npmmirror.com/vue3-lazy/-/vue3-lazy-1.0.0-alpha.1.tgz#326a56c2ade4430c76b7ac90d33a7fde0af9aaa6"
1088+
integrity sha512-dpjpKK4DC5q+wZVtS/VY3X6pYBJHxRmYanr20s39RB6o6fvbneQ/DNuz37bipYfEdrEvbSZ95Y2SCexuznQNrQ==
1089+
10901090
vue@^3.2.47:
10911091
version "3.3.4"
10921092
resolved "https://registry.npmmirror.com/vue/-/vue-3.3.4.tgz#8ed945d3873667df1d0fcf3b2463ada028f88bd6"

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /