svelte-webchat:基于svelte3+svelteKit仿微信mac网页版聊天实战案例。
采用了最新前端
svelte.js
框架,基于svelte3+svelteKit+sass+svelteLayer+svelteScroll
等技术开发仿微信网页端聊天项目。整体虚化背景UI质感,全新的Dock可左右滚动菜单。
svelte-webchat 支持发送消息+emoj、图片/视频/链接预览、拖拽+粘贴截图发送图片、红包/朋友圈、主题换肤等功能。
运用技术
- 前端框架:svelte^3.46.5+svelteKit
- 状态管理:svelte/store
- 下拉组件:mescroll.js
- 自定义滚动条:svelte-scrollbar
- 自定义弹窗:svelte-layer
- sass/less预处理:sass^1.50+svelte-preprocess
项目中的滚动条是基于svelte.js开发的自定义组件svelte-scrollbar
实现功能。
https://blog.csdn.net/yanxinyun1990/article/details/124622746
而各种弹窗效果,则是基于svelte.js开发的自定义弹窗组件svelte-layer
实现功能。
https://blog.csdn.net/yanxinyun1990/article/details/124240717
项目结构目录
预览
svelte公共布局
项目整体分为左侧+右侧主体内容+底部dock菜单三大模块。
<div class="sv__container flexbox flex-alignc flex-justifyc" style="--themeSkin: {$skin}">
<div class="sv__wrapper" class:maximize={$isWinMaximize}>
{#if $userinfo}
<div class="sv__board flexbox flex-col">
<!-- <div class="sv__topbar">顶部模块</div> -->
<div class="sv__mainwrap flex1 flexbox">
<!-- <div class="sv__sidebar">侧边栏</div> -->
<Middle />
<div class="sv__mainbx flex1 flexbox flex-col">
<Winbar />
<slot />
</div>
</div>
<Dock />
</div>
{:else}
<div class="sv__board flexbox flex-col">
<div class="sv__mainwrap flex1 flexbox">
<slot />
</div>
</div>
{/if}
</div>
</div>
通过svelte/store自定义状态管理,判断是否登录拦截。
<script>
import { onMount } from 'svelte'
import { page } from '$app/stores'
import { goto } from '$app/navigation'
import { userinfo, isWinMaximize, skin } from '@/store/index.js'
import Middle from '@/layout/Middle/index.svelte'
import Winbar from '@/layout/Winbar.svelte'
import Dock from '@/layout/Dock.svelte'
let whiteRoute = ['/auth/login', '/auth/register']
onMount(() => {
userinfo.useStorage()
isWinMaximize.useStorage()
skin.useStorage()
if(!$userinfo) {
goto('/auth/login')
}else {
if(whiteRoute.includes($page.url.pathname)) {
goto('/')
}else {
goto($page.url.pathname)
}
}
})
</script>
新建一个 store/index.js 文件。
/**
* Svelte状态管理
*/
import { writable } from 'svelte/store'
import Storage from "@/utils/storage"
const createStore = (key) => {
const { subscribe, set, update } = writable(typeof window !== 'undefined' ? Storage.get(key) : null)
return {
// 持久化存储
useStorage: () => {
const data = Storage.get(key)
if(data) {
set(JSON.parse(data))
}
// 订阅
subscribe(val => {
[null, undefined].includes(val) ? Storage.del(key) : Storage.set(key, JSON.stringify(val))
})
},
subscribe,
set,
update,
}
}
// 用户信息
export const userinfo = createStore('userinfo')
// 窗口是否最大化
export const isWinMaximize = createStore('isWinMaximize')
// 侧边栏收缩
export const isMidCollapsed = createStore('isMidCollapsed')
// 窗口皮肤
export const skin = createStore('skin')
svelte实现dock菜单
dock菜单支持path: '/friends'
路径跳转,自定义img图片和iconfont图标、红底圆点提醒等功能。
还支持拖拽图标、左右滚动滑动切换。
<div class="sv__dockbar flexbox flex-justifyc">
<div class="sv__dock-scroll" style="background: {bgcolor};">
<Scrollbar autohide size={2} mousewheel>
<div class="sv__dock-wrap" bind:this={dockEl}>
<!-- dock菜单项 -->
{#each menu as item,index}
{#if item.type == 'divider'}
<div class="sv__dock-divider"></div>
{:else}
<div class="sv__dock-item flexbox" class:cur={currentTabIndex == index} id={item.id || 'dock'+index} role="{item.title}" style="color: {currentTabIndex == index ? activeColor : color}" on:click={changeTab(index, item)}>
{#if item.icon}<span class="iconfont {item.icon}" style="color: {item.color}; font-size: {item.iconSize}">{item.icon.charAt(1) == '' ? item.icon : ''}</span>{/if}
{#if item.img}<img class="iconimg" src={item.img} alt="" style="font-size: {item.iconSize};" />{/if}
{#if item.badge}<span class="sv__badge sv__dock-badge">{item.badge}</span>{/if}
{#if item.dot}<span class="sv__badge-dot sv__dock-badgeDot"></span>{/if}
</div>
{/if}
{/each}
</div>
</Scrollbar>
</div>
</div>
聊天编辑框支持光标处插入内容,粘贴截图发送图片功能。
监听系统paste事件
editorEl.addEventListener('paste', function(e) {
e.preventDefault()
let cbd = e.clipboardData
let ua = window.navigator.userAgent
if(!(e.clipboardData && e.clipboardData.items)) return
if(cbd.items && cbd.items.length === 2 && cbd.items[0].kind === "string" && cbd.items[1].kind === "file" &&
cbd.types && cbd.types.length === 2 && cbd.types[0] === "text/plain" && cbd.types[1] === "Files" &&
ua.match(/Macintosh/i) && Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49){
return;
}
for(var i = 0; i < cbd.items.length; i++) {
var item = cbd.items[i]
// console.log(item)
// console.log(item.kind)
if(item.kind == 'file') {
var blob = item.getAsFile()
if(blob.size === 0) return
// 读取图片记录
var reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = function() {
var imgpath = this.result
// 返回图片给父组件
dispatch('paste', imgpath)
}
}
}
})
拖拽上传实现
/* ############# { 拖拽上传模块 } ############# */
function handleDragEnter(e) {
e.stopPropagation()
e.preventDefault()
}
function handleDragOver(e) {
e.stopPropagation()
e.preventDefault()
}
function handleDrop(e) {
e.stopPropagation()
e.preventDefault()
handleFileList(e.dataTransfer)
}
// 拖拽文件列表
function handleFileList(filelist) {
let files = filelist.files
if(files.length >= 2) {
svLayer.message({content: '暂时支持拖拽一张图片', icon: 'error', time: 0, xclose: true, shade: true})
return false
}
for(let i = 0; i < files.length; i++) {
if(files[i].type != '') {
handleFileAdd(files[i])
}else {
svLayer.message({content: '目前不支持文件夹拖拽功能', icon: 'error', time: 0, xclose: true, shade: true})
}
}
}
function handleFileAdd(file) {
let len = msgList.length
// 消息队列
let msgArr = {
id: `msg_${++len}`,
msgtype: 5,
isme: true,
avatar: '/uimg/img-avatar08.jpg',
author: 'Hison',
msg: '',
imgsrc: '',
videosrc: ''
}
if(file.type.indexOf('image') == -1) {
svLayer.message({content: '目前不支持非图片拖拽功能', icon: 'error', time: 0, xclose: true, shade: true})
}else {
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = async function() {
let img = this.result
msgArr.imgsrc = img
msgList = msgList.concat(msgArr)
await tick()
scrollBottom()
}
}
}
OK,基于svelte.js+svelteKit开发网页聊天项目就分享到这里哈~~
最后附上两个最新实例项目
-
uniapp+uview仿抖音app聊天实例
https://blog.csdn.net/yanxinyun1990/article/details/120387832 -
vite+vue3+electron中后台管理系统平台
https://blog.csdn.net/yanxinyun1990/article/details/116936475