基于svelte3+sass仿微信网页版聊天|svelte.js 桌面聊天实例SvelteWebChat

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开发网页聊天项目就分享到这里哈~~

最后附上两个最新实例项目

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaoyan_2018

你的鼓励将是我持续作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值