首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Svelte3-Webchat基于svelte.js网页版聊天实例

Svelte3-Webchat基于svelte.js网页版聊天实例

原创
作者头像
andy2018
发布于 2022-05-17 07:31:32
发布于 2022-05-17 07:31:32
4.1K1
举报
文章被收录于专栏:h5h5

项目简介

svelte-webchat一款基于svelte3.x+sveltekit+svelteLayer开发构建的仿微信PC版聊天实例。

svelteWechat 支持消息+emoj表情、图片/视频/链接预览、粘贴截图/拖拽图片发送、红包/朋友圈、全屏/更换主题等功能。

前段时间也有分享一个svelte.js移动端聊天实例。

https://cloud.tencent.com/developer/article/1976254

运用技术

  • 编辑器:vscode
  • 框架技术:svelte^3.46+svelteKit
  • 下拉刷新:mescroll.js
  • 滚动条组件:svelte-scrollba
  • 对话框组件:svelte-laye
  • sass预处理:sass^1.50+svelte-preprocess

项目结构

svelte-webchat还有朋友圈模块,下拉刷新、预览大图、侧边发布弹窗等功能。

svelte自定义组件(滚动条+对话框)

项目整体使用到的滚动条及弹窗组件,均是基于svelte.js自定义组件实现功能。

svelte-scrollbar一款轻量级svelte.js自定义模拟美化滚动条组件

svelte-layer一款功能丰富的svelte.js自定义PC端弹窗组件

svelte公共布局模板

使用sveltekit构建的项目,提供了__layout.svelte公共布局及__error.svelte错误处理。

如上图:项目整体布局分为左侧+右侧内容区+底部dock菜单三个大的模块。

代码语言:javascript
复制
<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>

另外还提供了错误处理页面。

代码语言:javascript
复制
<!-- //Svelte错误页 -->
<script context="module">
    export function load({ error, status }) {
        return {
            props: { error, status }
        }
    }
</script>

<script>
    import { goto } from '$app/navigation'
    export let status
    export let error

    function goBack() {
        // history.go(-1)
        goto('/')
    }
</script>

<svelte:head>
    <title>{status} Error!</title>
</svelte:head>

<div class="sv__scrollview flex1">
    <div class="sv__page-error flexbox flex-col flex-alignc flex-justifyc">
        <div class="sv__page-error-img">
            <img src="404.png" alt="" />
        </div>
        <div class="sv__page-error-content">
            <div class="c-red fs-18">┗| {status} |┛  Page Error~~</div>
            <div class="c-999 mt-10">{error.message}</div>
            <div class="sv__btn" on:click={goBack}><i class="iconfont icon-arrL"></i> 返回首页</div>
        </div>
    </div>
</div>

svelte登录及拦截验证

代码语言:javascript
复制
<script>
    import { onMount } from 'svelte'
    import { goto } from '$app/navigation'
    import Layer, { svLayer } from '$lib/Layer'
    import { userinfo } from '@/store'
    import util from '@/utils'

    let formObj = {}
    let vcodeText = '获取验证码'
    let disabled = false
    let time = 0

    let agree = false
    let vcodeLG = true

    let telEl
    onMount(() => {
        userinfo.useStorage()
        telEl.focus()
    })

    function Message(content) {
        svLayer.message({content, icon: 'warning', time: 0, xclose: true, shade: true})
    }

    // 60s倒计时
    function getVcode() {
        let { tel } = formObj
        if(!tel) {
            Message('手机号不能为空')
        }else if(!util.checkTel(tel)) {
            Message('手机号不正确')
        }else {
            time = 60
            disabled = true
            countDown()
        }
    }
    function countDown() {
        if(time > 0) {
            vcodeText = '获取验证码('+ time +')'
            time--
            setTimeout(countDown, 1000)
        }else {
            vcodeText = '获取验证码'
            time = 0
            disabled = false
        }
    }
    
    function handleSubmit() {
        console.log('——+——+——表单数据:', formObj)

        let { tel, vcode, pwd } = formObj
        if(!tel) {
            Message('手机号不能为空')
        }else if(!util.checkTel(tel)) {
            Message('手机号不正确')
        }else if(vcodeLG && !vcode) {
            Message('验证码不能为空')
        }else if(!vcodeLG && !pwd) {
            Message('密码不能为空')
        }else {
            svLayer({
                type: 'toast',
                icon: 'success',
                content: '登录成功',
                shadeClose: false,
                time: 2,
                onClose: () => {
                    userinfo.set({
                        user: tel,
                        token: util.setToken()
                    })
                    goto('/')
                }
            })
        }
    }
</script>

svelte自定义Dock菜单

底部dock菜单支持鼠标滑过提示标题、滚轮左右滚动/拖拽滚动、菜单配置项支持path跳转、自定义img和iconfont图标(颜色+大小),点击选项支持自定义事件并返回索引。

代码语言:javascript
复制
<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>
代码语言:javascript
复制
<script>
    // 当前索引
    export let current = 0
    // 背景色
    export let bgcolor = undefined
    // 颜色
    export let color = '#795548'
    // 激活颜色
    export let activeColor = '#ff3e00'
    // 菜单项
    export let menu = [
        {
            path: '/',
            icon: 'icon-xiaoxi1',
            // color: '#2979ff',
            title: '消息',
            badge: 8
        },
        {
            path: '/friends',
            icon: 'icon-haoyou',
            // color: '#17c956',
            title: '通讯录'
        },
        {
            path: '/my/favor',
            icon: 'icon-shoucang2',
            // color: '#8d1cff',
            title: '收藏'
        },
        {
            path: '/fzone',
            img: '/fzone.png',
            title: '朋友圈',
            dot: true
        },
        
        { type: 'divider' },
        
        {
            img: '/svelte.png',
            title: 'svelte.js',
        },
        {
            img: '/info.png',
            title: '关于',
        },
        {
            img: '/skin.png',
            title: '皮肤',
            id: 'skinwrap',
        },
        {
            icon: 'icon-filter',
            color: '#673ab7',
            title: '设置',
        },
        {
            icon: 'icon-custom',
            color: '#00bcd4',
            iconSize: '28px',
            title: '应用',
            id: 'appwrap'
        },
        
        { type: 'divider' },
        
        {
            icon: 'icon-tuichu',
            color: '#607d8b',
            title: '退出',
            id: 'logoutwrap'
        }
    ]

    import { page } from '$app/stores'
    import { goto } from '$app/navigation'
    import { beforeUpdate, onMount, onDestroy, createEventDispatcher } from 'svelte'
    const dispatch = createEventDispatcher()
    
    import Sortable from 'sortablejs'
    import { userinfo } from '@/store/index.js'
    import Layer, {svLayer} from '$lib/Layer'
    import Scrollbar from '$lib/Scrollbar'

    // 引入组件模板
    import Skin from './component/Skin.svelte'
    import Setting from './component/Setting.svelte'
    import AppManage from './component/AppManage.svelte'

    let dockEl
    $: currentTabIndex = current
    let settingLayer

    beforeUpdate(() => {
        const curPath = $page.url.pathname
        menu.map((item, index) => {
            // if(item.path == curPath) {
            //     currentTabIndex = index
            // }
            if(curPath.includes(item.path)) {
                currentTabIndex = index
            }
        })
    })

    onMount(() => {
        // 拖拽操作
        Sortable.create(dockEl, {
            handle: '.sv__dock-item',
            // filter: '.xxx',
            animation: 200,
            delay: 0,
            onEnd({ newIndex, oldIndex }) {
                console.log(`新索引:${newIndex} 旧索引:${oldIndex}`)
            }
        })

        let pbox
        let items = dockEl.querySelectorAll('.sv__dock-item')
        items.forEach(o => {
            o.addEventListener('mouseenter', () => {
                pbox = svLayer.popover({
                    id: 'popover__' + o.id,
                    content: o.getAttribute('role'),
                    follow: '#' + o.id,
                    placement: 'top',
                    // 是否显示箭头
                    // arrow: false,
                    // 自定义样式(背景色+文字色)
                    layerStyle: 'background:#333;color:#fff;border-radius:2px;font-size:12px;',
                    time: null,
                    xclose: false
                })
            })
            o.addEventListener('mouseout', () => {
                if(!pbox) return
                pbox.$set({open: false})
            })
        })
    })

    onDestroy(() => {
        // 退出登录关闭设置弹窗
        if(!$userinfo && settingLayer) {
            console.log('——+——+——+——+————+——退出啦啦啦')
            settingLayer.$set({open: false})
            settingLayer = null
        }
    })

    // 切换dock选项
    function changeTab(index, item) {
        currentTabIndex = index
        dispatch('click', index)
        if(item.path) {
            goto(item.path)
        }
    }
</script>

OK,基于svelte.js开发网页版聊天项目就先分享到这里。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 项目简介
  • 运用技术
  • 项目结构
  • svelte自定义组件(滚动条+对话框)
  • svelte公共布局模板
  • svelte登录及拦截验证
  • svelte自定义Dock菜单
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档