vue3评论组件,🔥基于vue3的UI组件,主要功能有评论,聊天,搜索,锚点。
入门
请遵循https://readpage.github.io/undraw-ui/上的文档!
源码地址: github、gitee
安装
使用npm
安装
npm i undraw-ui
使用
- 在
main.ts
中引入组件
import { createApp } from 'vue'
import App from './App.vue'
import UndrawUi from 'undraw-ui'
import 'undraw-ui/dist/style.css'
const app = createApp(App)
app.use(UndrawUi)
app.mount('#app')
1. 折叠
<template>
<u-fold unfold line="1">
<p>
时间不是某种从我们身上流过的东西,而就是我的生命。弃我而去的不是日历上的一个个日子,而是我生命中的岁月;甚至也不仅仅是我的岁月,而就是我自己。我不但找不回逝去的岁月,而且也找不回从前的我了。
</p>
</u-fold>
</template>
2. 评论
<template>
<div class="comment-view" style="padding: 0px">
<u-comment :config="config" @submit="submit" @like="like">
<!-- <template #list-title>全部评论</template> -->
</u-comment>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import { UToast, CommentApi, CommentSubmitParam, ConfigApi } from 'undraw-ui'
// 下载表情包资源emoji.zip https://gitee.com/undraw/undraw-ui/releases
// static文件放在public下,引入emoji.ts文件可以移动到自定义位置
import emoji from './emoji'
const config = reactive<ConfigApi>({
user: {
id: 1,
username: 'user',
avatar: 'https://static.juzicon.com/avatars/avatar-200602130320-HMR2.jpeg?x-oss-process=image/resize,w_100',
// 评论id数组 建议:存储方式用户id和文章id和评论id组成关系,根据用户id和文章id来获取对应点赞评论id,然后加入到数组中返回
likes: [1, 2, 11]
},
emoji: emoji,
comments: []
})
// 提交评论事件
const submit = ({ clear, content, parentId }: CommentSubmitParam) => {
console.log(content, parentId)
UToast({ message: '评论成功!', type: 'info' })
// 提交评论 --后端接口处理
editSubmit(content, parentId as number)
clear()
}
// 点赞按钮事件
const like = (id: number) => {
const likes = config.user.likes
if (likes.indexOf(id) == -1) {
// 点赞 --后端接口处理
likes.push(id)
editLike(id, 1)
} else {
// 取消点赞 --后端接口
likes.splice(
likes.findIndex(item => item == id),
1
)
editLike(id, -1)
}
}
// 模拟后端处理
const editLike = (id: number, count: number) => {
let tar = null
config.comments.forEach(v => {
if (v.id != id) {
tar = v.reply?.list.find(v => v.id == id)
} else {
tar = v
}
if (tar) {
tar.like += count
}
})
}
let temp_id = 100
// 模拟后端处理
const editSubmit = (content: string, parentId: number) => {
let comment: CommentApi = {
id: (temp_id += 1),
parentId: parentId,
avatar: config.user.avatar,
username: config.user.username,
level: 6,
link: `/${(temp_id += 1)}`,
address: '来自江苏',
content: content,
like: 0,
createTime: '1分钟前',
reply: null
}
if (parentId == undefined) {
config.comments.push(comment)
} else {
let raw_comment = config.comments.find(v => v.id == parentId)
let reply = raw_comment?.reply
if (reply) {
reply.list.push(comment)
} else if (raw_comment) {
raw_comment.reply = { total: 1, list: [comment] }
} else {
config.comments.push(comment)
}
}
}
config.comments = [
{
id: 1,
parentId: null,
avatar: 'https://static.juzicon.com/avatars/avatar-200602130320-HMR2.jpeg?x-oss-process=image/resize,w_100',
username: '落🤍尘',
level: 6,
link: '/1',
address: '来自上海',
content:
'缘生缘灭,缘起缘落,我在看别人的故事,别人何尝不是在看我的故事?别人在演绎人生,我又何尝不是在这场戏里?谁的眼神沧桑了谁?我的眼神,只是沧桑了自己[喝酒]',
like: 2,
createTime: '1分钟前',
reply: null
},
{
id: 3,
parentId: null,
username: '悟二空',
avatar: 'https://static.juzicon.com/user/avatar-bf22291e-ea5c-4280-850d-88bc288fcf5d-220408002256-ZBQQ.jpeg',
level: 1,
link: '/3',
address: '来自苏州',
content: '知道在学校为什么感觉这么困吗?因为学校,是梦开始的地方。[脱单doge]',
like: 11,
createTime: '1天前',
reply: {
total: 2,
list: [
{
id: 14,
parentId: 3,
avatar:
'https://static.juzicon.com/user/avatar-8b6206c1-b28f-4636-8952-d8d9edec975d-191001105631-MDTM.jpg?x-oss-process=image/resize,m_fill,w_100,h_100',
username: '别扰我清梦*ぁ',
level: 5,
link: '/14',
address: '来自重庆',
content: '说的对,所以,综上所述,上课睡觉不怪我呀💤',
like: 3,
createTime: '1分钟前'
},
{
id: 15,
avatar:
'https://static.juzicon.com/user/avatar-3cb86a0c-08e7-4305-9ac6-34e0cf4937cc-180320123405-BCV6.jpg?x-oss-process=image/resize,m_fill,w_100,h_100',
parentId: 3,
username: 'Blizzard',
level: 4,
link: '/15',
content: '回复 <span style="color: blue;"">@别扰我清梦*ぁ:</span> 看完打了一个哈切。。。会传染。。。[委屈]',
address: '来自广州',
like: 9,
createTime: '7天前'
}
]
}
}
]
</script>
3. 搜索(input关键词动态滚动)
<template>
<u-search :config="config" style="margin-left: 20px" @submit="submit"></u-search>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { SearchConfig } from 'undraw-ui'
const config = ref<SearchConfig>({
keywords: ['斗罗大陆', '斗破苍穹', '吞噬星空', '凡人修仙传', '一念永恒'], // 搜索框关键字滚动
hotSearchList: [
'斗罗大陆',
'斗破苍穹',
'吞噬星空',
'凡人修仙传',
'一念永恒',
'完美世界',
'鬼灭之刃',
'间谍过家家',
'武动乾坤',
'神印王座'
] // top10 热门搜索 最多显示10条数据
})
const submit = (val: string) => {
console.log(val)
window.open('/all?keyword=' + val)
}
</script>
<style lang="scss" scoped></style>
4. 锚点
<template>
<div class="view">
<el-scrollbar height="500px">
<div id="article2" class="article">
<h2>人的大地</h2>
<p>
我们对自身的了解,来自大地的,比来自书本的多。因为大地桀骜不驯。人在跟障碍较量时,才会发现自己的价值。但是,为了克服障碍,人需要一个工具——一个木刨,或一把铁犁。农民在劳动中,逐渐窥探到自然界的一些奥秘,他们挖掘到的真理是无处不在的。同样地,飞机这个航空运输工具,也使人接触到这些古老的问题。
</p>
<p>
在茫茫夜海上,每一盏灯火都显示了一个心灵的奇迹。在这户人家,有人在阅读,有人在思索,有人在娓娓谈心。在另一户人家,有人在探索宇宙,有人在殚精竭虑地计算仙女座的星云。那里,有人在恋爱。原野上绵延不断地闪烁着这些暗淡欲灭的灯火。还有最隐秘的,那是诗人的灯火、教师的灯火、木工师傅的灯火。但是,在这些有生命的灯火之间,又有多少扇关闭的窗户,多少个沉睡的人……我应该努力返航,设法跟其中幾盏灯火产生联系——这些灯火,绵延向远方,星星点点,散落在原野上。
</p>
<h2>人和植物一样</h2>
<p>对我来说,在地里种下一粒种子本身就是美好的。我总是带着喜悦和极大的敬畏去做这件事。</p>
<p>种子种下去以后,我会看着我的花圃,想象生命是如何在眼睛看不见的黑暗地下工作的。</p>
<p>
我一直惦记着自己种下的种子。我常常在夜里醒来,陷入思索:雨水和露珠如何接触干燥的种壳,使它变得柔软。生命的精灵如何在种子里活跃起来,植物的个性如何呈现出来,种子如何挣脱囚禁自己的种壳,从中伸出两只手——一只手是根,负责抓住泥土,让自己挺立并吸收养料;另一只手伸出去寻找光,向上攀爬,痛饮微风和阳光,实现它完整的生命之美。
</p>
<h2>文明与野蛮</h2>
<p>
我们相信,人类社会会不断摒除野蛮,走向文明,因为绝大多数人向往文明,文明意味着尊重生命、维护人的尊严和自由、建立一种理性且科学的生活方式,让绝大多数人有安全感。人类历史正是因为人类对文明的追求与保护而顽强延续到今天,文明战胜野蛮,是必然的。
</p>
<h2>等待中的期许</h2>
<div class="content">
<h3>开头</h3>
<p>
 曾听图书出版界的朋友讲过一个令人心动的故事。前些年,他在一个饭局上,遇到一个初次见面的人。中国人聊天,总会问籍贯,就像英国人爱聊天气。听那人说到自己的故乡,朋友心弦微动。他忽然想起一个名字。30多年前,他还是一个少年,从杂志上找了一个笔友。两个人通信很久,聊聊日常琐事、青春悸动。直到后来,毕业,上班,搬家,逐渐失联。
</p>
<p>
这是许多人都有的经历,成长,始于告别。这位朋友一直记得笔友所在的城市——就是在饭局上初见的那个人的故乡。朋友随意问起,是否认识某某某(他笔友的名字)。那人当即回道:“我们是邻居。”
</p>
<p>
中国地大物博、人口众多,他们却通过这种巧合,再次相遇了。如今,两个人都结了婚,有了孩子,换了城市过着平淡的生活。这样的巧合,算是生活里的小奇迹。朋友还找机会去了笔友所在的城市,与她和她的家人见面,从此建立联系。只是交流方式不再是车马慢的信件,而是微信,两个人升级为网友。
</p>
<p>
近日和年轻的同事聊起这个故事,让我惊讶的是,这群“90后”竟然也有笔友。一名同事还提到一个网站,注册后,会收到一个随机地址,可以给对方寄送明信片。他也收到过来自英国、日本、马来西亚等地的明信片。日本笔友,很体贴地用中文写着地址;法国笔友,歪歪扭扭地写了“你好”两个字。
</p>
<p>
据这家网站统计,已经有80多万名会员收到来自207个国家的6293万张明信片。这种跨越千万里的期待,总是令人怦然心动。
</p>
<h3>中间</h3>
<p>
多年前,我出差去外地,还时不时给同事寄上一两张明信片,总算生活中,能有一些小小的惊喜。这些惊喜所蕴含的正是“等待”的迷人之处。像《等待戈多》里所说的:“我在等待我的戈多,我却真的不知道他什么时候来。”沈从文写《边城》,也说翠翠等着心上人,“那个人也许永远不回来了,也许明天回来”。
</p>
<p>
日本人伊藤秀夫从来没想过,自己的孩子能够“回来”。10年前,他的儿子就因落水而丧生了。但是不久前,他收到一张明信片,是儿子寄出的。原来,在孩子遭遇意外之前,当地政府搞了一个防止全球变暖的宣传和启蒙活动。他们邀请小学生给10年后的自己寄一张明信片。伊藤的儿子参加了。10多年后,政府才把这些明信片寄出。伊藤这才知道,儿子当时最关心的一件事是,“我弟弟在干什么?”看着明信片,伊藤一下子记起了那个冬天,那个孩子的样子。我也忽然想起“刻舟求剑”这个词来。那张明信片,就是伊藤儿子刻下的记号,伊藤永远找不回儿子了,记号却一直存在。
</p>
<p>
如今,邮筒正在慢慢消失,说起来总令人深感惋惜。可是,如果让我们回到那个车马慢的时代,估计大部分人会拒绝。
</p>
<p>在这个时代,人们不断往前跑,总会甩下一些东西,有得有失。</p>
<p>
前两天看新闻,一家外卖平台要增加社交功能了。我于是掰着手指头数了数,我们有了电商社交、短视频社交,现在又有外卖社交——真是一个社交途径极丰富的时代。
</p>
<h3>结尾</h3>
<p>
只是,曾经那种社交的丰富感——期待、温馨、畅快、痛苦……已很难感受到了。一个点赞图标,几乎表达了我们作为人类的一切感情。
</p>
<p>(徐 行摘自《看天下》,IC photo供图)</p>
</div>
<h2>村庄的时间</h2>
<div class="content">
<p>
当我十岁的时候站在我家后面的皂荚树下,我突然感到时间的停滞。我的视野里只有寂静的午后村庄,没有风,没有人,空气均匀地铺展在池塘的深绿色水面上。我在这种突如其来的空寂中不敢妄动,与此同时,心中涌起永恒的瞻望。我想我永远不会长大,鸭蹼状的宽大树叶也永遠不会扇动,而放眼望去,青砖平房、柴垛、洗衣石板都永远在这里,不会变动一分一毫。
</p>
<p>
片刻后,一声狗吠从巷口穿透时间凝滞形成的雾状薄膜,小孩子在天台上望着奔跑而去的伙伴放声大哭,我从一种清亮的空寂时间一下子坠入纷杂的轰隆隆的时间洪流,一直到现在。
</p>
<p>
我在城市的时间里看到时间是属于摇滚乐的,一年前还是土堆成山的地方,呼啦啦拔地而起一片楼群;又见拆迁的工地,昔日的楼房破腔露肚,灰白的墙壁上满是雨痕。重建与摧毁,搬入与流离,过去与现在宛如时间的两排利齿,一切都被咬得粉碎。
</p>
<p>
而当我回到村庄,在我生命的二十多年间,它几乎没有什么变动,老屋拆去,新屋盖起,住的依然是原来的人家。时间在村庄宛如丝绸,平滑完整,几乎不留痕迹。
</p>
<p>
我从一个城市迁徙到另一个城市,舍弃旧的人事,建立新的人事,流动的、变化的,没有一个坚硬的空间能顽强留存。
</p>
<p>
时间在村庄没有痕迹吗?试想我与相差二十岁的侄子,我跟他在同样的村庄长大,看到的同样是田地、池塘、泥路,同样可以攀在江边的桑树上吃桑葚,然而这二十年的时间是虚无的吗?我看着他跟小时候的我一样用瓦片和泥土玩过家家,一样看到黄昏时太阳在田野尽头的树林间隐没。然而,他再也听不到每天早上一直喊到我起床的米糕小贩的叫卖声了,再也听不到敲着清脆响亮铁板卖姜糖的叮叮当声了,再也不会跟我一样挤坐在垸礼堂听戏了。手工艺人在农村已经消失,无论是篾匠、木匠,还是弹棉花的匠人,都已经无处寻觅。手工艺人展现技艺的时间感是缓慢的、耐心的。我记得,随着拨浪鼓的咚咚声,婶娘们拥出门围着小贩买针头线脑,而满身棉絮的匠人在堂屋用巨大的弓弹着棉花,宛如翻搅起漫天雪花。
</p>
<p>
而我的侄子只能看到事物的最终状态,时间在“需求—供应”模式下被挤压成薄片。他睡在从家居市场买来的床上,吃着从菜市场买来的菜,玩着从超市买来的玩具。虽在农村,却与在城市几无差异,还好他能看到跑动的鸡和狗,认识生长在田地里的棉花和小麦。
</p>
<p>
他跟随他的父母离开村庄,进入不同的城市,不断变更就读的学校,不断认识新同学又忘记老同学。这样一种流动不居的空间变动,给他带来的是怎样的时间体验呢?我想在我之前,祖辈都在这个村庄日出而作、日落而息,耕种同一片土地,喝同一脉井水,我想时间于他们是绵长的、悠远的。而到了我这一代,空间开始变动,时间慢慢加快,村庄中的人不断外涌。由此我看到在我父亲与他的父亲之间,时间是没有肌理的;而在我跟我侄子之间,时间裹挟的人事变化远超从前。
</p>
<p>(朱 颜摘自人民文学出版社《纸上王国》一书,黄思思图)</p>
</div>
</div>
</el-scrollbar>
<!-- container指定监听的容器 target滚动轴 target-offset距离窗口顶部达到指定偏移量 -->
<div class="article-catalog">
<u-anchor container="#article2" style="width: 120px" target=".el-scrollbar__wrap"></u-anchor>
</div>
</div>
</template>
<script lang="ts" setup>
import { ElScrollbar } from 'undraw-ui'
</script>
<style lang="scss" scoped>
.article-catalog {
width: 300px;
margin-left: 10px;
}
.view {
display: flex;
}
.article {
width: 400px;
p {
margin: 20px 0;
font-size: 16px;
line-height: 32px;
word-break: break-all;
text-indent: 2em;
}
}
</style>