feat: like topic
This commit is contained in:
parent
efef4bc6f9
commit
cc7fcb678a
|
@ -7,6 +7,7 @@ export * from './edit/types/edit'
|
||||||
export * from './home/types/home'
|
export * from './home/types/home'
|
||||||
export * from './kungalgamer/types/kungalgamer'
|
export * from './kungalgamer/types/kungalgamer'
|
||||||
export * from './login/types/login'
|
export * from './login/types/login'
|
||||||
|
export * from './topic/types/action'
|
||||||
export * from './topic/types/topic'
|
export * from './topic/types/topic'
|
||||||
export * from './topic/types/aside'
|
export * from './topic/types/aside'
|
||||||
export * from './update-log/types/updateLog'
|
export * from './update-log/types/updateLog'
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { fetchGet, fetchPost } from '@/utils/request'
|
import { fetchGet, fetchPost, fetchPut } from '@/utils/request'
|
||||||
// 将对象转为请求参数的函数
|
// 将对象转为请求参数的函数
|
||||||
import objectToQueryParams from '@/utils/objectToQueryParams'
|
import objectToQueryParams from '@/utils/objectToQueryParams'
|
||||||
|
import * as Action from './types/action'
|
||||||
import * as Aside from './types/aside'
|
import * as Aside from './types/aside'
|
||||||
import * as Topic from './types/topic'
|
import * as Topic from './types/topic'
|
||||||
|
|
||||||
|
@ -54,6 +55,18 @@ export async function getTopicByTidApi(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 点赞话题
|
||||||
|
export async function updateTopicLikeApi(
|
||||||
|
request: Action.TopicLikeTopicRequestData
|
||||||
|
): Promise<Action.TopicLikeTopicResponseData> {
|
||||||
|
const queryParams = objectToQueryParams(request, 'tid')
|
||||||
|
const url = `/topics/${request.tid}/like?${queryParams}`
|
||||||
|
|
||||||
|
const response = fetchPut<Action.TopicLikeTopicResponseData>(url)
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
// 根据话题 tid 获取话题回复
|
// 根据话题 tid 获取话题回复
|
||||||
export async function getRepliesByPidApi(
|
export async function getRepliesByPidApi(
|
||||||
request: Topic.TopicReplyRequestData
|
request: Topic.TopicReplyRequestData
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
/**
|
/**
|
||||||
* 这是用户对话题的操作,推,点赞,点踩等
|
* 这是用户对话题的操作,推,点赞,点踩等
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// 点赞
|
||||||
|
export interface TopicLikeTopicRequestData {
|
||||||
|
tid: number
|
||||||
|
to_uid: number
|
||||||
|
isPush: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点赞话题响应数据的格式
|
||||||
|
export type TopicLikeTopicResponseData = KUNGalgameResponseData<{}>
|
||||||
|
|
|
@ -16,6 +16,9 @@ export default (
|
||||||
type: MessageType,
|
type: MessageType,
|
||||||
duration?: number
|
duration?: number
|
||||||
) => {
|
) => {
|
||||||
|
// 初始化的时候先将上一次创建的内容销毁
|
||||||
|
render(null, document.body)
|
||||||
|
|
||||||
const messageNode = h(Message, {
|
const messageNode = h(Message, {
|
||||||
messageCN,
|
messageCN,
|
||||||
messageEN,
|
messageEN,
|
||||||
|
|
|
@ -200,6 +200,10 @@ const handleTextChange = async () => {
|
||||||
/* 头部下方阴影 */
|
/* 头部下方阴影 */
|
||||||
box-shadow: 0 2px 4px 0 var(--kungalgame-trans-blue-1);
|
box-shadow: 0 2px 4px 0 var(--kungalgame-trans-blue-1);
|
||||||
display: v-bind(isShowEditorToolbar);
|
display: v-bind(isShowEditorToolbar);
|
||||||
|
/* 不显示视频插入,这个功能 BUG 太多了 */
|
||||||
|
.ql-video {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 编辑器体的样式 */
|
/* 编辑器体的样式 */
|
||||||
|
|
|
@ -10,6 +10,14 @@ import {
|
||||||
getPopularTopicsByUserUidApi,
|
getPopularTopicsByUserUidApi,
|
||||||
TopicAsideResponseData,
|
TopicAsideResponseData,
|
||||||
} from '@/api'
|
} from '@/api'
|
||||||
|
|
||||||
|
// 点赞等动作
|
||||||
|
import {
|
||||||
|
updateTopicLikeApi,
|
||||||
|
TopicLikeTopicRequestData,
|
||||||
|
TopicLikeTopicResponseData,
|
||||||
|
} from '@/api'
|
||||||
|
|
||||||
// 回复
|
// 回复
|
||||||
import {
|
import {
|
||||||
getRepliesByPidApi,
|
getRepliesByPidApi,
|
||||||
|
@ -19,6 +27,7 @@ import {
|
||||||
TopicCreateReplyRequestData,
|
TopicCreateReplyRequestData,
|
||||||
TopicCreateReplyResponseData,
|
TopicCreateReplyResponseData,
|
||||||
} from '@/api'
|
} from '@/api'
|
||||||
|
|
||||||
// 评论
|
// 评论
|
||||||
import {
|
import {
|
||||||
getCommentsByReplyRidApi,
|
getCommentsByReplyRidApi,
|
||||||
|
@ -98,6 +107,20 @@ export const useKUNGalgameTopicStore = defineStore({
|
||||||
return await getTopicByTidApi(tid)
|
return await getTopicByTidApi(tid)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 点赞话题
|
||||||
|
async updateTopicLike(
|
||||||
|
tid: number,
|
||||||
|
toUid: number,
|
||||||
|
isPush: boolean
|
||||||
|
): Promise<TopicLikeTopicResponseData> {
|
||||||
|
const requestData: TopicLikeTopicRequestData = {
|
||||||
|
tid: tid,
|
||||||
|
to_uid: toUid,
|
||||||
|
isPush: isPush,
|
||||||
|
}
|
||||||
|
return await updateTopicLikeApi(requestData)
|
||||||
|
},
|
||||||
|
|
||||||
// 获取回复
|
// 获取回复
|
||||||
async getReplies(tid: number): Promise<TopicReplyResponseData> {
|
async getReplies(tid: number): Promise<TopicReplyResponseData> {
|
||||||
// 这里的默认值用于初始化
|
// 这里的默认值用于初始化
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
export function getPlainText(html: string): string {
|
export function getPlainText(html: string): string {
|
||||||
// 使用正则表达式匹配所有HTML标签并删除
|
// 使用正则表达式匹配所有 HTML 标签并删除
|
||||||
const plainText = html.replace(/<[^>]*>/g, '')
|
const plainText = html.replace(/<[^>]*>/g, '')
|
||||||
|
|
||||||
// 使用实体编码映射表将HTML实体编码还原
|
// 使用实体编码映射表将 HTML 实体编码还原
|
||||||
const entityMap: Record<string, string> = {
|
const entityMap: Record<string, string> = {
|
||||||
lt: '<',
|
lt: '<',
|
||||||
gt: '>',
|
gt: '>',
|
||||||
|
|
|
@ -58,19 +58,19 @@ const loliFaceLeft = loli.face.left + 'px'
|
||||||
const loliFaceTop = loli.face.top + 'px'
|
const loliFaceTop = loli.face.top + 'px'
|
||||||
|
|
||||||
// 身体的图片资源链接
|
// 身体的图片资源链接
|
||||||
let lass = getAssetsFile(loli.lass.layer_id)
|
const lass = getAssetsFile(loli.lass.layer_id)
|
||||||
|
|
||||||
// 眼睛的图片资源链接
|
// 眼睛的图片资源链接
|
||||||
let eye = getAssetsFile(loli.eye.layer_id)
|
const eye = getAssetsFile(loli.eye.layer_id)
|
||||||
|
|
||||||
// 眉毛的图片资源链接
|
// 眉毛的图片资源链接
|
||||||
let brow = getAssetsFile(loli.brow.layer_id)
|
const brow = getAssetsFile(loli.brow.layer_id)
|
||||||
|
|
||||||
// 嘴巴的图片资源链接
|
// 嘴巴的图片资源链接
|
||||||
let mouth = getAssetsFile(loli.mouth.layer_id)
|
const mouth = getAssetsFile(loli.mouth.layer_id)
|
||||||
|
|
||||||
// 腮红的图片资源链接
|
// 腮红的图片资源链接
|
||||||
let face = getAssetsFile(loli.face.layer_id)
|
const face = getAssetsFile(loli.face.layer_id)
|
||||||
|
|
||||||
// 导出模块
|
// 导出模块
|
||||||
export {
|
export {
|
||||||
|
|
36
src/utils/throttle.ts
Normal file
36
src/utils/throttle.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* Throttle(节流)函数
|
||||||
|
* 在一段时间内,无论触发多少次函数,都只执行一次
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {T} executeCallback - 要应用 throttle 函数的代码
|
||||||
|
* @param {number} delay - throttle 的时间
|
||||||
|
* @param {T | undefined} delayedCallback - 用户在 throttle 时间未到执行了 execute 函数产生的回调
|
||||||
|
*/
|
||||||
|
export function throttle<T extends (...args: any[]) => void>(
|
||||||
|
executeCallback: T,
|
||||||
|
delay: number,
|
||||||
|
delayedCallback?: T | undefined
|
||||||
|
) {
|
||||||
|
let lastExecution = 0
|
||||||
|
let timeout: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
|
const throttled = (...args: Parameters<T>) => {
|
||||||
|
const now = Date.now()
|
||||||
|
|
||||||
|
if (!lastExecution || now - lastExecution >= delay) {
|
||||||
|
executeCallback(...args)
|
||||||
|
lastExecution = now
|
||||||
|
} else {
|
||||||
|
if (!timeout && delayedCallback) {
|
||||||
|
delayedCallback(...args)
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
timeout = null
|
||||||
|
}, delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return throttled as (...args: Parameters<T>) => void
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ const {
|
||||||
user,
|
user,
|
||||||
// rid,
|
// rid,
|
||||||
status,
|
status,
|
||||||
// share,
|
share,
|
||||||
category,
|
category,
|
||||||
} = topicData.topicData
|
} = topicData.topicData
|
||||||
|
|
||||||
|
@ -94,11 +94,19 @@ const loliStatus = computed(() => {
|
||||||
<Rewrite v-if="edited" :time="edited" />
|
<Rewrite v-if="edited" :time="edited" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 话题的点赞数等信息,楼主的 floor 就是 0 -->
|
<!-- 话题的点赞数等信息,楼主的 floor 就是 0,被作用人就是该话题的发布人 -->
|
||||||
<MasterFooter
|
<MasterFooter
|
||||||
:info="{ tid, views, likes, dislikes, upvotes, to_floor: 0 }"
|
:info="{
|
||||||
|
tid,
|
||||||
|
views,
|
||||||
|
likes,
|
||||||
|
dislikes,
|
||||||
|
upvotes,
|
||||||
|
share,
|
||||||
|
to_floor: 0,
|
||||||
|
}"
|
||||||
:topic="{ tid, title, content, tags, category }"
|
:topic="{ tid, title, content, tags, category }"
|
||||||
:r-user="user"
|
:master="user"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
<!-- 话题的底部区域,推话题,回复,点赞等 -->
|
<!-- 话题的底部区域,推话题,回复,点赞等 -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
import { Icon } from '@iconify/vue'
|
import { Icon } from '@iconify/vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
// 全局消息组件(顶部)
|
||||||
|
import message from '@/components/alert/Message'
|
||||||
|
// throttle 函数
|
||||||
|
import { throttle } from '@/utils/throttle'
|
||||||
|
|
||||||
import { TopicUserInfo } from '@/api'
|
import { TopicUserInfo } from '@/api'
|
||||||
|
|
||||||
|
@ -28,6 +33,7 @@ const props = defineProps<{
|
||||||
likes: number[]
|
likes: number[]
|
||||||
dislikes: number[]
|
dislikes: number[]
|
||||||
upvotes: number[]
|
upvotes: number[]
|
||||||
|
share: number[]
|
||||||
// 被回复人的 floor
|
// 被回复人的 floor
|
||||||
to_floor: number
|
to_floor: number
|
||||||
}
|
}
|
||||||
|
@ -38,23 +44,87 @@ const props = defineProps<{
|
||||||
tags: string[]
|
tags: string[]
|
||||||
category: string[]
|
category: string[]
|
||||||
}
|
}
|
||||||
rUser: TopicUserInfo
|
master: TopicUserInfo
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// 是否具有重新编辑的权限
|
|
||||||
/**
|
/**
|
||||||
* 这里只是简单起见,不显示重新编辑
|
* 这里只是简单起见,不显示重新编辑
|
||||||
* 实际上如果用户自己修改了 localStorage 中保存的信息,这个验证就失效了
|
* 实际上如果用户自己修改了 localStorage 中保存的信息,这个验证就失效了
|
||||||
* 但是修改了也没有用,验证逻辑位于后端
|
* 但是修改了也没有用,验证逻辑位于后端
|
||||||
*/
|
*/
|
||||||
const isShowRewrite = useKUNGalgameUserStore().uid === props.rUser.uid
|
// 当前登录用户的 uid
|
||||||
|
const currUserUid = useKUNGalgameUserStore().uid
|
||||||
|
// 是否具有重新编辑的权限
|
||||||
|
const isShowRewrite = currUserUid === props.master.uid
|
||||||
|
|
||||||
|
// footer 左侧的动作,点赞等
|
||||||
|
const actions = reactive({
|
||||||
|
upvotes: props.info.upvotes,
|
||||||
|
likes: props.info.likes,
|
||||||
|
dislikes: props.info.dislikes,
|
||||||
|
share: props.info.share,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 是否已经点过赞,点过踩
|
||||||
|
const isActive = reactive({
|
||||||
|
isUpvote: false,
|
||||||
|
isLiked: false,
|
||||||
|
isDisliked: false,
|
||||||
|
isShared: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
// throttle 函数,1007 毫秒仅会触发一次点赞
|
||||||
|
const handleClickLikeThrottled = throttle(
|
||||||
|
async () => {
|
||||||
|
// 当前用户不可以给自己点赞
|
||||||
|
if (currUserUid === props.master.uid) {
|
||||||
|
message(
|
||||||
|
'You cannot like your own topic',
|
||||||
|
'您不可以给自己的话题点赞',
|
||||||
|
'warn'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换点赞激活状态
|
||||||
|
isActive.isLiked = !isActive.isLiked
|
||||||
|
|
||||||
|
const res = await useKUNGalgameTopicStore().updateTopicLike(
|
||||||
|
props.info.tid,
|
||||||
|
props.master.uid,
|
||||||
|
isActive.isLiked
|
||||||
|
)
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
// 更新点赞数
|
||||||
|
actions.likes.length = isActive.isLiked
|
||||||
|
? actions.likes.length + 1
|
||||||
|
: actions.likes.length - 1
|
||||||
|
} else {
|
||||||
|
message('Like topic failed!', '点赞话题失败', 'error')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
1007,
|
||||||
|
() => {
|
||||||
|
message(
|
||||||
|
'You can only perform one operation within 1007 milliseconds',
|
||||||
|
'您在 1007 毫秒内只能进行一次操作',
|
||||||
|
'warn'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 在点击事件中使用节流版本的函数
|
||||||
|
const handleClickLike = () => {
|
||||||
|
handleClickLikeThrottled()
|
||||||
|
}
|
||||||
|
|
||||||
// 点击回复打开回复面板
|
// 点击回复打开回复面板
|
||||||
const handelReply = async () => {
|
const handelReply = async () => {
|
||||||
// 保存必要信息,以便发表回复
|
// 保存必要信息,以便发表回复
|
||||||
replyDraft.value.tid = props.info.tid
|
replyDraft.value.tid = props.info.tid
|
||||||
// 被回复人就是发表人的 uid
|
// 被回复人就是发表人的 uid
|
||||||
replyDraft.value.to_uid = props.rUser.uid
|
replyDraft.value.to_uid = props.master.uid
|
||||||
replyDraft.value.to_floor = props.info.to_floor
|
replyDraft.value.to_floor = props.info.to_floor
|
||||||
|
|
||||||
isEdit.value = true
|
isEdit.value = true
|
||||||
|
@ -75,6 +145,29 @@ const handleClickEdit = () => {
|
||||||
// 跳转到编辑界面
|
// 跳转到编辑界面
|
||||||
router.push({ name: 'Edit' })
|
router.push({ name: 'Edit' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化按钮的状态,是否已点赞等
|
||||||
|
onMounted(() => {
|
||||||
|
// 已经推过
|
||||||
|
if (props.info.upvotes.includes(currUserUid)) {
|
||||||
|
isActive.isUpvote = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已经点赞
|
||||||
|
if (props.info.likes.includes(currUserUid)) {
|
||||||
|
isActive.isLiked = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已经点踩
|
||||||
|
if (props.info.dislikes.includes(currUserUid)) {
|
||||||
|
isActive.isDisliked = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已经分享
|
||||||
|
if (props.info.share.includes(currUserUid)) {
|
||||||
|
isActive.isShared = true
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -86,7 +179,7 @@ const handleClickEdit = () => {
|
||||||
<!-- 推话题 -->
|
<!-- 推话题 -->
|
||||||
<li>
|
<li>
|
||||||
<span class="icon"><Icon icon="bi:rocket" /></span>
|
<span class="icon"><Icon icon="bi:rocket" /></span>
|
||||||
{{ info.upvotes.length }}
|
{{ actions.upvotes.length }}
|
||||||
</li>
|
</li>
|
||||||
<!-- 查看数量 -->
|
<!-- 查看数量 -->
|
||||||
<li>
|
<li>
|
||||||
|
@ -95,39 +188,38 @@ const handleClickEdit = () => {
|
||||||
</li>
|
</li>
|
||||||
<!-- 点赞 -->
|
<!-- 点赞 -->
|
||||||
<li>
|
<li>
|
||||||
<span class="icon"><Icon icon="line-md:thumbs-up-twotone" /></span>
|
<span
|
||||||
{{ info.likes.length }}
|
class="icon"
|
||||||
|
:class="isActive.isLiked ? 'active' : ''"
|
||||||
|
@click="handleClickLike"
|
||||||
|
><Icon icon="line-md:thumbs-up-twotone"
|
||||||
|
/></span>
|
||||||
|
{{ actions.likes.length }}
|
||||||
</li>
|
</li>
|
||||||
<!-- 踩 -->
|
<!-- 踩 -->
|
||||||
<li>
|
<li>
|
||||||
<span class="icon"><Icon icon="line-md:thumbs-down-twotone" /></span>
|
<span class="icon"><Icon icon="line-md:thumbs-down-twotone" /></span>
|
||||||
{{ info.dislikes.length }}
|
{{ actions.dislikes.length }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部右侧部分(回复、评论、只看、编辑) -->
|
<!-- 底部右侧部分(回复、评论、只看、编辑) -->
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<ul>
|
<div @click="handelReply" class="reply">
|
||||||
<li @click="handelReply">
|
{{ $tm('topic.content.reply') }}
|
||||||
<div class="reply">
|
</div>
|
||||||
{{ $tm('topic.content.reply') }}
|
|
||||||
</div>
|
<!-- 分享 -->
|
||||||
</li>
|
<span class="icon"><Icon icon="majesticons:share-line" /></span>
|
||||||
<!-- 分享 -->
|
|
||||||
<li>
|
<!-- 只看 -->
|
||||||
<span class="icon"><Icon icon="majesticons:share-line" /></span>
|
<span class="icon"><Icon icon="ph:user-focus-duotone" /></span>
|
||||||
</li>
|
|
||||||
<!-- 只看 -->
|
<!-- 编辑 -->
|
||||||
<li>
|
<span v-if="isShowRewrite" @click="handleClickEdit" class="icon">
|
||||||
<span class="icon"><Icon icon="ph:user-focus-duotone" /></span>
|
<Icon icon="line-md:pencil-twotone-alt" />
|
||||||
</li>
|
</span>
|
||||||
<!-- 编辑 -->
|
|
||||||
<li v-if="isShowRewrite">
|
|
||||||
<span @click="handleClickEdit" class="icon">
|
|
||||||
<Icon icon="line-md:pencil-twotone-alt" />
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -170,17 +262,20 @@ const handleClickEdit = () => {
|
||||||
color: var(--kungalgame-font-color-2);
|
color: var(--kungalgame-font-color-2);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 激活后的样式 */
|
||||||
|
.active {
|
||||||
|
color: var(--kungalgame-blue-4);
|
||||||
|
}
|
||||||
|
|
||||||
/* 底部右侧部分(回复、评论、只看、编辑) */
|
/* 底部右侧部分(回复、评论、只看、编辑) */
|
||||||
.right ul {
|
.right {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 10px;
|
span {
|
||||||
li {
|
display: flex;
|
||||||
margin-right: 17px;
|
margin-right: 17px;
|
||||||
span {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ const handelClosePanel = () => {
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="body" :disabled="isEdit">
|
<Teleport to="body" :disabled="isEdit">
|
||||||
<Transition
|
<Transition
|
||||||
enter-active-class="animate__animated animate__bounceInUp animate__faster"
|
enter-active-class="animate__animated animate__fadeInUp animate__faster"
|
||||||
leave-active-class="animate__animated animate__fadeOutDown animate__faster"
|
leave-active-class="animate__animated animate__fadeOutDown animate__faster"
|
||||||
>
|
>
|
||||||
<div class="root" v-if="isEdit">
|
<div class="root" v-if="isEdit">
|
||||||
|
|
Loading…
Reference in a new issue