Svelte Ui Admin后台管理系统|svelte3+svelteUI中后台前端解决方案
基于svelte3.x+svelteKit+svelte-ui网页后台管理系统SvelteAdmin。
Svelte-Ui-Admin 基于svelte3.x+svelteKit+vite3+echarts搭配使用Svelte UI组件库开发的一套轻量级前端中后台管理系统解决方案。Svelte Ui Admin遵循Svelte Ui组件设计和开发规范,高颜值的组件让整体风格细腻统一。

技术框架
- 开发工具:Vscode
- 框架技术:svelte3.x+svelteKit+vite3
- UI组件库:svelte-ui (基于svelte自定义pc端UI组件库)
- 样式处理:sass^1.54.4
- 图表组件:echarts^5.3.3
- 编辑器组件:wangeditor^4.7.15
- 国际化方案:svelte-i18n^3.4.0
- 数据模拟:mockjs^1.1.0

功能特性
- 最新前端技术栈Svelte3、SvelteKit、Vite3、SvelteUI、Svelte-i18n、Echarts5.x、MockJs。
- 支持中文/英文/繁体多语言解决方案。
- 支持表格单选/多选、边框/隔行换色、横向/纵向虚拟滚动条等功能。
- 整体搭配高颜值的Svelte Ui组件库,风格更加统一。
- 高效率开发,整个框架已经搭建完毕,只需新增相应模块即可。
- 动态路由及菜单联动控制。


项目目录结构
整体遵循标准的svelteKit项目结构目录及编码规范。

效果预览



















Svelte Ui组件库
基于svelte3.x开发的桌面pc端UI组件库SvelteUI。超过30+组件,覆盖了大多数组件应用场景,遵循svelte.js语法规范开发。


通过如下方式快速引入组件。
import {
Button,
Input,
Radio,
Select,
Checkbox,
...
} from 'svelte-ui'
具体的用法及介绍,可以去看看下面的这篇分享文章。
https://www.cnblogs.com/xiaoyan2017/p/16585254.html
Svelte Ui Admin页面布局结构
项目公共布局模板+layout.svelte,错误页+error.svelte。

+layout.svelte整体分为顶部栏+左侧菜单+右侧主体内容三大板块。
<div class="svadmin__container" style="--themeSkin: {$skin}">
<div class="svadmin__wrapper-layout flexbox flex-col">
<div class="sv__layout-header">
<Header />
</div>
<div class="sv__layout-body flex1 flexbox">
<!-- //侧边栏 -->
{#if rootRouteEnable}
<div class="sv__bd-sidebar">
<SideMenu routes={mainRoutes} {activeRoute} />
</div>
{/if}
{#if (rootRouteEnable && route != '/') || !rootRouteEnable}
<div class="sv__bd-menus" class:collapsed={collapsed&&!rootRouteEnable}>
<RouteMenu
routes={getAllRoutes}
{activeRoute}
{activeRootRoute}
{rootRouteEnable}
{collapsed}
/>
</div>
{/if}
<div class="sv__bd-main flex1 flexbox flex-col">
<!-- 面包屑导航 -->
<BreadCrumb routes={getAllRoutes} {activeRoute} {activeRootRoute} />
<!-- 主内容区 -->
<Scrollbar autohide gap={2}>
<div class="sv__main-wrapper">
<slot />
</div>
</Scrollbar>
</div>
</div>
</div>
</div>
+error.svelte错误页处理。
<script>
import { page } from '$app/stores'
import { goto } from '$app/navigation'
import { Button } from '$lib/svelte-ui' function goHome() {
goto('/home/index')
}
</script> <svelte:head>
<title>{$page.status} Error!</title>
</svelte:head> <div class="svadmin__pageErr flexbox flex-col flex-alignc flex-justifyc">
<div class="svadmin__pageErr-img"><i class="sv-icon-round_close_fill_light"></i></div>
<div class="svadmin__pageErr-content">
<div class="c-red fs-18">┗| {$page.status} |┛ Page Error~~</div>
<div class="c-999 mt-10 mb-10">{$page.error.message}</div>
<Button size="small" on:click={goHome}>Go Home</Button>
</div>
</div>
自定义路由菜单Menu


如上图:使用了svelte-ui组件库中的Menu组件来动态生成菜单。
<Menu
class="svadmin__menu-list"
data={getNewRoutes}
active={activeRoute}
trigger="click"
collapse={collapsed}
backgroundHover="#e2f2ff"
>
{#each getNewRoutes as route}
<svelte:component this={routeMenuItem} item={route} {activeRootRoute} {rootRouteEnable} />
{/each}
</Menu>
<!-- 二级菜单 -->
<script>
import { goto } from '$app/navigation'
import { _ } from 'svelte-i18n' import { Menu, MenuItem, MenuSub } from '$lib/svelte-ui'
import routeMenuItem from './routeMenuItem.svelte' import utils from '@/utils'
import { getCurrentRootRoute, hasChildrenRoute } from '@/utils/routes' export let item = []
// 根菜单
export let activeRootRoute = ''
// 是否开启一级路由菜单
export let rootRouteEnable = true function changeRoute(path) {
if(utils.isExternal(path)) {
window.open(path, '_blank')
}else {
goto(path)
}
}
</script> {#if !item.meta.hidden}
{#if activeRootRoute !== getCurrentRootRoute(item) && rootRouteEnable === true}
<div></div>
{:else}
{#if item.children && Array.isArray(item.children) && hasChildrenRoute(item.children)}
<MenuSub key={item.key}>
<span slot="icon"><i class={item.meta.icon}></i></span>
<div slot="title">{$_(`menu.${item.meta.title}`)}</div> {#each item.children || [] as route2}
<svelte:component this={routeMenuItem} item={route2} {activeRootRoute} {rootRouteEnable} />
{/each}
</MenuSub>
{:else}
<MenuItem key={item.key} title={$_(`menu.${item.meta.title}`)} on:click={changeRoute(item.path)}></MenuItem>
{/if}
{/if}
{/if}
/**
* 路由菜单Layout.js
*/
export function load() {
return {
mainRoutes: [
// 主页模块
{
key: 'home', // 标识Menu组件匹配路径
path: '/home', // 跳转路由
redirect: '/home/index', // 重定向路由
meta: {
auth: true, // 是否验证状态
icon: 'sv-icon-homefill', // 路由图标
title: 'layouts__main-menu__home', // 路由标题
hidden: false, //是否隐藏菜单项
},
children: [
// 首页
{
key: 'home_index',
path: 'index',
meta: {
auth: true,
icon: 'sv-icon-home',
title: 'layouts__main-menu__home_index'
}
},
// 工作台
{
key: 'home_workplace',
path: 'workplace',
meta: {
auth: true,
icon: 'sv-icon-dashboard',
title: 'layouts__main-menu__home_dashboard'
}
},
// 自定义面包屑
{
key: 'home_breadcrumb',
path: 'breadcrumb',
meta: {
auth: true,
icon: 'sv-icon-breadcrumb',
title: 'layouts__main-menu__home_breadcrumb',
// 自定义面包屑
breadcrumb: [
{
meta: {title: 'layouts__main-menu__home_breadcrumb'},
path: '/home/breadcrumb',
},
{
meta: {title: 'layouts__main-menu__home'},
path: '/home',
},
{
meta: {title: 'layouts__main-menu__home_breadcrumb-links'},
}
]
}
},
// 外部链接
{
key: 'https://svelte.dev/',
path: 'https://svelte.dev/',
meta: {
icon: 'sv-icon-openlink',
title: 'layouts__main-menu__home_apidocs',
rootRoute: '/home'
}
}
]
}, // 组件模块
{
key: 'component',
path: '/component',
redirect: '/component/table/all',
meta: {
auth: true, //是否验证状态
icon: 'sv-icon-apps-fill',
title: 'layouts__main-menu__component',
hidden: false, //是否隐藏菜单项
},
children: [
{
key: 'component_table',
path: 'table',
redirect: '/component/table/all',
meta: {
auth: true,
icon: 'sv-icon-table',
title: 'layouts__main-menu__component_table',
},
children: [
{
key: 'component_table_all',
path: 'all',
meta: {
title: 'layouts__main-menu__component_table-all'
}
},
{
key: 'component_table_custom',
path: 'custom',
meta: {
title: 'layouts__main-menu__component_table-custom'
}
},
{
key: 'component_table_search',
path: 'search',
redirect: '/component/table/search/list',
meta: {
title: 'layouts__main-menu__component_table-search',
},
children: [
{
key: 'component_table_search_list',
path: 'list',
meta: {
title: 'layouts__main-menu__component_table-search-list'
}
}
]
}
]
},
{
key: 'component_list',
path: 'list',
meta: {
icon: 'sv-icon-sort',
title: 'layouts__main-menu__component_list',
}
},
{
key: 'component_form',
path: 'form',
redirect: '/component/form/all',
meta: {
auth: true,
icon: 'sv-icon-forms',
title: 'layouts__main-menu__component_form',
},
children: [
{
key: 'component_form_all',
path: 'all',
meta: {
title: 'layouts__main-menu__component_form-all',
}
},
{
key: 'component_form_custom',
path: 'custom',
meta: {
title: 'layouts__main-menu__component_form-custom',
}
}
]
},
{
key: 'component_editor',
path: 'editor',
meta: {
icon: 'sv-icon-editor',
title: 'layouts__main-menu__component_editor',
}
}
]
}, // 配置模块
{
key: 'setting',
path: '/setting',
redirect: '/setting/mine',
meta: {
icon: 'sv-icon-setting',
title: 'layouts__main-menu__setting',
hidden: false,
},
children: [
...
]
}, // 权限验证模块
{
key: 'permission',
path: '/permission',
redirect: '/permission/all',
meta: {
auth: true,
icon: 'sv-icon-secret',
title: 'layouts__main-menu__permission',
hidden: false,
},
children: [
...
]
}, // 错误页面模块
{
key: 'error',
path: '/error',
redirect: '/error/403',
meta: {
icon: 'sv-icon-roundclosefill',
title: 'layouts__main-menu__error',
hidden: false,
},
children: [
...
]
},
]
}
}

svelte-i18n国际化解决方案
项目中采用svelte-i18n实现国际化,支持中文/英文/繁体字三种语言。

npm i svelte-i18n -D

/**
* 国际化语言配置
* @author YXY
*/ import { addMessages, init, getLocaleFromNavigator } from 'svelte-i18n'
import { browser } from '$app/env'
import Storage from '@/utils/storage' // 引入语言配置
import cn from '@/locale/zh-CN'
import tw from '@/locale/zh-TW'
import en from '@/locale/en-US' export const langKey = 'lang'
export const langVal = 'cn' addMessages('cn', cn)
addMessages('tw', tw)
addMessages('en', en) const lang = getLang()
console.log('当前国际化:', lang)
init({
fallbackLocale: lang,
initialLocale: getLocaleFromNavigator()
})
setHtmlLang(lang) /* 获取语言 */
export function getLang() {
const lang = Storage.get(langKey)
return lang || langVal
} /* 持久化存储 */
export function setLang(lang, reload = false) {
if(lang != getLang()) {
Storage.set(langKey, lang || '')
setHtmlLang(lang) // 重载页面
if(reload) {
window.location.reload()
}
}
}
svelte动态图表Hooks
由于项目中多个地方使用了Echarts图表组件,于是单独抽离了一个hooks文件来初始化echarts组件。
针对自适应图表,则使用了 "element-resize-detector": "^1.2.4" 来实时监听DOM尺寸改变。


/**
* @title 动态图表Hooks
* @author YXY
*/
import * as echarts from 'echarts'
import elementResizeDetector from "element-resize-detector"
import utils from '@/utils' export const useCharts = async(node, options) => {
let chartInstance
let chartNode = null
let erd = elementResizeDetector() const resizeFn = utils.debounce(() => {
chartInstance.resize()
}, 100) if(node) {
chartInstance = echarts.init(node)
chartInstance.setOption(options)
chartNode = chartInstance
}
erd.listenTo(node, resizeFn)
}
通过如下方式即可快速调用图表hooks。
<script>
import { useCharts } from '@/hooks.js' function useBarChart(node) {
useCharts(node, {
...
})
} function useStackChart(node) {
useCharts(node, {
...
})
}
</script> <div class="card-charts" use:useBarChart></div>
<div class="card-charts" use:useStackChart></div>
项目中还有一大亮点就是Table表格组件,支持固定表头/列,单选及多选,边框/隔行换色,支持动态slot插槽等功能。

<script>
/**
* 表格组件
* @author YXY
* Q:282310962 WX:xy190310
*/ let tableNode
let curpage = 1
let limit = 10
let selectRows = []
let tableData = Mock.mock({
total: 100,
page: 1,
pagesize: 5,
'list|10': [
{
id: '@integer(1, 1000)',
author: '@cname()',
title: '@ctitle(10, 15)',
image: `https://cdn2.thecatapi.com/images/@integer(200, 300).jpg`,
summary: '@ctitle(20, 70)',
'role|1': ['admin', 'test', 'dev'],
topmost: '@boolean()',
progress: '@integer(30, 90)',
date: '@datetime()'
}
]
})
let tableColumns = [
{type: 'selection', align: 'center', width: 60, fixed: true}, // 多选
// {type: 'index', align: 'center', width: 60}, // 索引序号
{prop: 'id', label: 'id', align: 'center', width: 60}, // 索引序号
{prop: 'author', label: '作者', align: 'center', width: 100},
{slot: 'title', label: '标题', align: 'left', width: 250},
{slot: 'image', label: '图像', align: 'center', width: 120},
{slot: 'summary', label: '详细内容', align: 'left', width: 450},
{slot: 'role', label: '角色', align: 'center', width: 100},
{slot: 'topmost', label: '置顶', align: 'center', width: 100},
{slot: 'progress', label: '热度', align: 'center', width: 150},
{prop: 'date', label: '发布时间', align: 'left', width: 200}, // 时间
{slot: 'btns', label: '操作', align: 'center', width: 200, fixed: 'right'}, // 操作
]
// 获取选中行数据
function getSelectionRow() {
svLayer({
title: '信息',
content: JSON.stringify(selectRows),
xclose: true,
area: '640px'
})
}
// 选中第3行
function updateRow() {
tableNode.setCurrent(2)
}
// 取消选择
function cancelSelection() {
tableNode.setCurrent()
}
// 当前页
function handleChangePage(e) {
console.log('当前页:', e.detail)
curpage = Number(e.detail)
}
// 页码
function handleChangeSize(e) {
console.log('每页:', e.detail)
limit = Number(e.detail)
}
// 点击行
function handleSelectionChange(e) {
console.log('selection change选中行数据>>:', e.detail)
selectRows = e.detail
}
</script> <Table
dataSource={tableData.list}
columns={tableColumns}
stripe={isStripe}
border={isBorder}
size={tableSizeCmd}
highlightCurrentRow
let:row
let:col
let:index
on:selectionChange={handleSelectionChange}
on:headerClick={handleHeaderClick}
bind:this={tableNode}
style="height: 500px; margin-bottom: 15px;"
>
{#if col.slot == 'title'}
<Link href="https://svelte.dev/" target="_blank" isUnderline color="#06f">{row.title}</Link>
{:else if col.slot == 'image'}
<img src={row.image} style="height: 50px; width: 50px;" alt="" />
{:else if col.slot == 'summary'}
<Tooltip content={row.summary} placement="top-start">
<div class="clamp2">{row.summary}</div>
</Tooltip>
{:else if col.slot == 'role'}
{#if row.role == 'admin'}
<Tag type="success" effect="dark" size="mini">{row.role}</Tag>
{:else if row.role == 'test'}
<Tag type="primary" size="mini">{row.role}</Tag>
{:else}
<Tag type="warning" effect="dark" size="mini">{row.role}</Tag>
{/if}
{:else if col.slot == 'topmost'}
<Switch checked={row.topmost} activeColor="#ff4079" size="small" />
{:else if col.slot == 'progress'}
<Progress percent={row.progress} color="#ffa222" showtext="false" strokeWidth={10} style="width: 100px;" />
{:else if col.slot == 'btns'}
<Link type="primary" icon="sv-icon-attention_light" gap="5" on:click={handleTableView}>查看</Link>
<Link type="success" icon="sv-icon-edit" gap="5" on:click={handleTableEdit(row)}>编辑</Link>
<Link type="danger" icon="sv-icon-delete" gap="5" on:click={handleTableDel(row)}>删除</Link>
{/if}
</Table>
<Pagination
layout="total, sizes, prev, pager, next, jumper"
currentPage={curpage}
pageSize={limit}
pageSizes={[10, 50, 100]}
total="500"
size="mini"
position="center"
on:changePage={handleChangePage}
on:changeSize={handleChangeSize}
/>
Ok,基于svelte+svelteUI开发后台管理系统就分享到这里,希望对大家有所帮助~~
最后附上一个svelte.js网页聊天实例项目
https://www.cnblogs.com/xiaoyan2017/p/16272097.html

Svelte Ui Admin后台管理系统|svelte3+svelteUI中后台前端解决方案的更多相关文章
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(4)-构建项目解决方案 创建EF DataBase Frist模式
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(4)-构建项目解决方案 创建EF DataBase Frist模式 进行本次文章之前,我们可能需要补充一些 ...
- 一种小型后台管理系统通用开发框架中的Cache缓存设计
本篇博客记录一下我在实习的公司的后台管理系统开发框架中学习到的一种关于网站的缓存(Cache)的实现方法,我会在弄懂的基础上,将该方法在.net core上进行实现.因为公司开发都是基于.net fr ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(4)-创建项目解决方案
系列目录 前言 为了符合后面更新后的重构系统,文章于2016-11-1日重写 设计中术语,概念这种东西过于模糊,我们必须学习累积才能认识这些概念模型. 我无法用文章来下详细解析此系统的深层概念,需要大 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)
开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 任务调度系统界面 http: ...
- django后台管理系统(admin)的简单使用
目录 django后台管理系统的使用 检查配置文件 检查根urls.py文件 启动项目,浏览器输入ip端口/admin 如: 127.0.0.1/8000/admin 回车 注册后台管理系统超级管理 ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(1)-前言与目录(持续更新中...)
转自:http://www.cnblogs.com/ymnets/p/3424309.html 曾几何时我想写一个系列的文章,但是由于工作很忙,一直没有时间更新博客.博客园园龄都1年了,却一直都是空空 ...
- Django后台管理系统讲解及使用
大家在创建Django项目后,在根路由urls.py文件中,会看到一行代码 from django.contrib import admin urlpatterns = [ url(r'^admin/ ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(转)
开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 日程管理 http://ww ...
- SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 后端篇(一): 搭建基本环境、整合 Swagger、MyBatisPlus、JSR303 以及国际化操作
相关 (1) 相关博文地址: SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 前端篇(一):搭建基本环境:https://www.cnblogs.com/l-y- ...
随机推荐
- Linux 磁盘挂载和swap空间管理
挂载:把指定的设备和根下面的某个文件夹建立关联 卸载:解除两者关系的过程 挂载文件系统:mount 格式:mount device mountpoint --- mount 设备名 挂载点 mount ...
- 鹏城杯 WEB_WP
简单的PHP GET /?code=[~%8C%86%8C%8B%9A%92][~%CF]([~%9A%91%9B][~%CF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A ...
- 反向传播神经网络(BP)
实验部分: ①输入.输出矢量及问题的阐述 由题意输入变量取值范围为e={-2,-1,0,1,2}和ec={-2,-1,0,1,2},则输入矢量有25种情况,分别如下所示: 则由T=int((e+ec) ...
- centos7 nginx 域名能ping通,但无法打开网页
方法一:关闭防火墙 sudo systemctl stop firewalld.service 方法二:容许80端口访问 vim打开iptables, 命令如下: #vim /etc/sysconfi ...
- 最强人工智能 OpenAI 极简教程
大家好哇,新同学都叫我张北海,老同学都叫我老胡,其实是一个人,只是我特别喜欢章北海这个<三体>中的人物,张是错别字. 上个月安利了一波:机器学习自动补全代(hán)码(shù)神器,然后就 ...
- 在win10系统环境下,安装配置sublime 3,构建python和vue.js开发环境(插件)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_131 疫情当下,最近一直在用mac下的虚拟机运行win10系统,由于在线人数过多,直播授课的时候使用vscode的时候内存暴涨,于 ...
- 手把手教你定位线上MySQL慢查询问题,包教包会
1. 慢查询日志的作用 慢查询日志默认不开启,建议手动开启,方便我们定位线上问题. 执行时间超过阈值的SQL会被写入到慢查询日志当中,这样可以帮助我们记录执行时间过长的SQL语句,定位线上慢SQL问题 ...
- r0capture安卓应用层通杀脚本-使用文档
本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! r0capture安卓应用层通杀脚本-使 ...
- 「Python实用秘技10」深度比较Python对象间差异
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第10 ...
- 技术分析 | 通过DML语句浅谈binlog和redo log
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1 ...