mall-admin web前端分析

2024-03-06 07:20

本文主要是介绍mall-admin web前端分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

登录模块

views>login>index.vue

<template><div><el-card class="login-form-layout"><el-form autoComplete="on":model="loginForm":rules="loginRules"ref="loginForm"label-position="left"><div style="text-align: center"><svg-icon icon-class="login-mall" style="width: 56px;height: 56px;color: #409EFF"></svg-icon></div><h2 class="login-title color-main">mall-admin-web</h2><el-form-item prop="username"><el-input name="username"type="text"v-model="loginForm.username"autoComplete="on"placeholder="请输入用户名"><span slot="prefix"><svg-icon icon-class="user" class="color-main"></svg-icon></span></el-input></el-form-item><el-form-item prop="password"><el-input name="password":type="pwdType"@keyup.enter.native="handleLogin"v-model="loginForm.password"autoComplete="on"placeholder="请输入密码"><span slot="prefix"><svg-icon icon-class="password" class="color-main"></svg-icon></span><span slot="suffix" @click="showPwd"><svg-icon icon-class="eye" class="color-main"></svg-icon></span></el-input></el-form-item><el-form-item style="margin-bottom: 60px"><el-button style="width: 100%" type="primary" :loading="loading" @click.native.prevent="handleLogin">登录</el-button></el-form-item></el-form></el-card><img :src="login_center_bg" class="login-center-layout"><el-dialogtitle="特别赞助":visible.sync="supportDialogVisible"width="30%"><span>mall项目已由CODING特别赞助,点击去支持,页面加载完后点击<span class="color-main font-medium">免费体验</span>按钮即可完成支持,谢谢!</span><span slot="footer" class="dialog-footer"><el-button @click="dialogCancel">残忍拒绝</el-button><el-button type="primary" @click="dialogConfirm">去支持</el-button></span></el-dialog><el-dialogtitle="公众号二维码":visible.sync="dialogVisible":show-close="false":center="true"width="30%"><div style="text-align: center"><span>mall全套学习教程连载中<span class="color-main font-medium">关注公众号</span>第一时间获取</span><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg" width="150" height="150" style="margin-top: 10px"></div><span slot="footer" class="dialog-footer"><el-button type="primary" @click="dialogConfirm">确定</el-button></span></el-dialog></div>
</template><script>import {isvalidUsername} from '@/utils/validate';import {setSupport,getSupport,SupportUrl} from '@/utils/support';import login_center_bg from '@/assets/images/login_center_bg.png'export default {name: 'login',data() {const validateUsername = (rule, value, callback) => {if (!isvalidUsername(value)) {callback(new Error('请输入正确的用户名'))} else {callback()}};const validatePass = (rule, value, callback) => {if (value.length < 3) {callback(new Error('密码不能小于3位'))} else {callback()}};return {loginForm: {username: 'admin',password: '123456',},loginRules: {username: [{required: true, trigger: 'blur', validator: validateUsername}],password: [{required: true, trigger: 'blur', validator: validatePass}]},loading: false,pwdType: 'password',login_center_bg,dialogVisible:false,supportDialogVisible:false}},methods: {showPwd() {if (this.pwdType === 'password') {this.pwdType = ''} else {this.pwdType = 'password'}},handleLogin() {this.$refs.loginForm.validate(valid => {if (valid) {let isSupport = getSupport();if(isSupport===undefined||isSupport==null){this.dialogVisible =true;return;}this.loading = true;this.$store.dispatch('Login', this.loginForm).then(() => {this.loading = false;this.$router.push({path: '/'})}).catch(() => {this.loading = false})} else {console.log('参数验证不合法!');return false}})},dialogConfirm(){this.dialogVisible =false;setSupport(true);// window.location.href=SupportUrl;},dialogCancel(){this.dialogVisible = false;setSupport(false);}}}
</script><style scoped>.login-form-layout {position: absolute;left: 0;right: 0;width: 360px;margin: 140px auto;border-top: 10px solid #409EFF;}.login-title {text-align: center;}.login-center-layout {background: #409EFF;width: auto;height: auto;max-width: 100%;max-height: 100%;margin-top: 200px;}
</style>

前端代码主要由三部分组成:

<template>
</template><script>
</script><style scoped>
</style>

个人理解:

  • 其中template主要用来绘制内容,大多是用户可以看见的内容。
  • 而style是用来修饰template的,比如颜色的选择,某块放置的位置,透明度,背景,动画等样式处理;这里有一个scope,是为了防止样式的应用到了其他页面,scope将其渲染的效果局限于当前页面,建议最好都加上
  • script主要用来方式其内部逻辑,比如被点击后的响应,向后端发送请求,存储该页面展示的数据等功能

我们发现template之中,主要有这些标签:

<div>
</div><span>
</span><img>

以上这三种都是html自有的标签

<el-dialog>
</el-dialog><el-button>
</el-button>

而这些都是element-ui的组件
这些组件只要引入以后就可以在自己的项目中使用,兼容性很好

现在来分析下这个登录按钮的代码

 <el-button style="width: 100%" type="primary" :loading="loading" @click.native.prevent="handleLogin">登录</el-button>

这里有一个@click.native.prevent的触发事件

具体解释如下:
@click-native-prevent click事件的native修饰

handleLogin的具体代码:

handleLogin() {this.$refs.loginForm.validate(valid => {if (valid) {let isSupport = getSupport();if (isSupport === undefined || isSupport == null) {this.dialogVisible = true;return;}this.loading = true;this.$store.dispatch('Login', this.loginForm).then(() => {this.loading = false;this.$router.push({path: '/'})}).catch(() => {this.loading = false})} else {console.log('参数验证不合法!');return false}})
},

这个方法里使用了这些技术:

这里首先实现验证输入是否合法,然后

首页模块

全部代码如下:

<template><div class="app-container"><div class="address-layout"><el-row :gutter="20"><el-col :span="6"><div class="out-border"><div class="layout-title">后台项目</div><div class="color-main address-content"><a href="https://github.com/macrozheng/mall">mall</a></div></div></el-col><el-col :span="6"><div class="out-border"><div class="layout-title">前端项目</div><div class="color-main address-content"><a href="https://github.com/macrozheng/mall-admin-web">mall-admin-web</a></div></div></el-col><el-col :span="6"><div class="out-border"><div class="layout-title">学习教程</div><div class="color-main address-content"><a href="https://github.com/macrozheng/mall-learning">mall-learning</a></div></div></el-col></el-row></div><div class="total-layout"><el-row :gutter="20"><el-col :span="6"><div class="total-frame"><img :src="img_home_order" class="total-icon"><div class="total-title">今日订单总数</div><div class="total-value">200</div></div></el-col><el-col :span="6"><div class="total-frame"><img :src="img_home_today_amount" class="total-icon"><div class="total-title">今日销售总额</div><div class="total-value">¥5000.00</div></div></el-col><el-col :span="6"><div class="total-frame"><img :src="img_home_yesterday_amount" class="total-icon"><div class="total-title">昨日销售总额</div><div class="total-value">¥5000.00</div></div></el-col><!--<el-col :span="6">--><!--<div class="total-frame">--><!--<svg-icon icon-class="total-week" class="total-icon">--><!--</svg-icon>--><!--<div class="total-title">近7天销售总额</div>--><!--<div class="total-value">¥50000.00</div>--><!--</div>--><!--</el-col>--></el-row></div><el-card class="mine-layout"><div style="text-align: center"><img width="150px" height="150px" src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg"></div><div style="text-align: center">mall全套学习教程连载中!</div><div style="text-align: center;margin-top: 5px"><span class="color-main">关注公号</span>,第一时间获取。</div></el-card><div class="un-handle-layout"><div class="layout-title">待处理事务</div><div class="un-handle-content"><el-row :gutter="20"><el-col :span="8"><div class="un-handle-item"><span class="font-medium">待付款订单</span><span style="float: right" class="color-danger">(10)</span></div></el-col><el-col :span="8"><div class="un-handle-item"><span class="font-medium">已完成订单</span><span style="float: right" class="color-danger">(10)</span></div></el-col><el-col :span="8"><div class="un-handle-item"><span class="font-medium">待确认收货订单</span><span style="float: right" class="color-danger">(10)</span></div></el-col></el-row><el-row :gutter="20"><el-col :span="8"><div class="un-handle-item"><span class="font-medium">待发货订单</span><span style="float: right" class="color-danger">(10)</span></div></el-col><el-col :span="8"><div class="un-handle-item"><span class="font-medium">新缺货登记</span><span style="float: right" class="color-danger">(10)</span></div></el-col><el-col :span="8"><div class="un-handle-item"><span class="font-medium">待处理退款申请</span><span style="float: right" class="color-danger">(10)</span></div></el-col></el-row><el-row :gutter="20"><el-col :span="8"><div class="un-handle-item"><span class="font-medium">已发货订单</span><span style="float: right" class="color-danger">(10)</span></div></el-col><el-col :span="8"><div class="un-handle-item"><span class="font-medium">待处理退货订单</span><span style="float: right" class="color-danger">(10)</span></div></el-col><el-col :span="8"><div class="un-handle-item"><span class="font-medium">广告位即将到期</span><span style="float: right" class="color-danger">(10)</span></div></el-col></el-row></div></div><div class="overview-layout"><el-row :gutter="20"><el-col :span="12"><div class="out-border"><div class="layout-title">商品总览</div><div style="padding: 40px"><el-row><el-col :span="6" class="color-danger overview-item-value">100</el-col><el-col :span="6" class="color-danger overview-item-value">400</el-col><el-col :span="6" class="color-danger overview-item-value">50</el-col><el-col :span="6" class="color-danger overview-item-value">500</el-col></el-row><el-row class="font-medium"><el-col :span="6" class="overview-item-title">已下架</el-col><el-col :span="6" class="overview-item-title">已上架</el-col><el-col :span="6" class="overview-item-title">库存紧张</el-col><el-col :span="6" class="overview-item-title">全部商品</el-col></el-row></div></div></el-col><el-col :span="12"><div class="out-border"><div class="layout-title">用户总览</div><div style="padding: 40px"><el-row><el-col :span="6" class="color-danger overview-item-value">100</el-col><el-col :span="6" class="color-danger overview-item-value">200</el-col><el-col :span="6" class="color-danger overview-item-value">1000</el-col><el-col :span="6" class="color-danger overview-item-value">5000</el-col></el-row><el-row class="font-medium"><el-col :span="6" class="overview-item-title">今日新增</el-col><el-col :span="6" class="overview-item-title">昨日新增</el-col><el-col :span="6" class="overview-item-title">本月新增</el-col><el-col :span="6" class="overview-item-title">会员总数</el-col></el-row></div></div></el-col></el-row></div><div class="statistics-layout"><div class="layout-title">订单统计</div><el-row><el-col :span="4"><div style="padding: 20px"><div><div style="color: #909399;font-size: 14px">本月订单总数</div><div style="color: #606266;font-size: 24px;padding: 10px 0">10000</div><div><span class="color-success" style="font-size: 14px">+10%</span><span style="color: #C0C4CC;font-size: 14px">同比上月</span></div></div><div style="margin-top: 20px;"><div style="color: #909399;font-size: 14px">本周订单总数</div><div style="color: #606266;font-size: 24px;padding: 10px 0">1000</div><div><span class="color-danger" style="font-size: 14px">-10%</span><span style="color: #C0C4CC;font-size: 14px">同比上周</span></div></div><div style="margin-top: 20px;"><div style="color: #909399;font-size: 14px">本月销售总额</div><div style="color: #606266;font-size: 24px;padding: 10px 0">100000</div><div><span class="color-success" style="font-size: 14px">+10%</span><span style="color: #C0C4CC;font-size: 14px">同比上月</span></div></div><div style="margin-top: 20px;"><div style="color: #909399;font-size: 14px">本周销售总额</div><div style="color: #606266;font-size: 24px;padding: 10px 0">50000</div><div><span class="color-danger" style="font-size: 14px">-10%</span><span style="color: #C0C4CC;font-size: 14px">同比上周</span></div></div></div></el-col><el-col :span="20"><div style="padding: 10px;border-left:1px solid #DCDFE6"><el-date-pickerstyle="float: right;z-index: 1"size="small"v-model="orderCountDate"type="daterange"align="right"unlink-panelsrange-separator=""start-placeholder="开始日期"end-placeholder="结束日期"@change="handleDateChange":picker-options="pickerOptions"></el-date-picker><div><ve-line:data="chartData":legend-visible="false":loading="loading":data-empty="dataEmpty":settings="chartSettings"></ve-line></div></div></el-col></el-row></div></div>
</template><script>import {str2Date} from '@/utils/date';import img_home_order from '@/assets/images/home_order.png';import img_home_today_amount from '@/assets/images/home_today_amount.png';import img_home_yesterday_amount from '@/assets/images/home_yesterday_amount.png';const DATA_FROM_BACKEND = {columns: ['date', 'orderCount','orderAmount'],rows: [{date: '2018-11-01', orderCount: 10, orderAmount: 1093},{date: '2018-11-02', orderCount: 20, orderAmount: 2230},{date: '2018-11-03', orderCount: 33, orderAmount: 3623},{date: '2018-11-04', orderCount: 50, orderAmount: 6423},{date: '2018-11-05', orderCount: 80, orderAmount: 8492},{date: '2018-11-06', orderCount: 60, orderAmount: 6293},{date: '2018-11-07', orderCount: 20, orderAmount: 2293},{date: '2018-11-08', orderCount: 60, orderAmount: 6293},{date: '2018-11-09', orderCount: 50, orderAmount: 5293},{date: '2018-11-10', orderCount: 30, orderAmount: 3293},{date: '2018-11-11', orderCount: 20, orderAmount: 2293},{date: '2018-11-12', orderCount: 80, orderAmount: 8293},{date: '2018-11-13', orderCount: 100, orderAmount: 10293},{date: '2018-11-14', orderCount: 10, orderAmount: 1293},{date: '2018-11-15', orderCount: 40, orderAmount: 4293}]};export default {name: 'home',data() {return {pickerOptions: {shortcuts: [{text: '最近一周',onClick(picker) {const end = new Date();let start = new Date();start.setFullYear(2018);start.setMonth(10);start.setDate(1);end.setTime(start.getTime() + 3600 * 1000 * 24 * 7);picker.$emit('pick', [start, end]);}}, {text: '最近一月',onClick(picker) {const end = new Date();let start = new Date();start.setFullYear(2018);start.setMonth(10);start.setDate(1);end.setTime(start.getTime() + 3600 * 1000 * 24 * 30);picker.$emit('pick', [start, end]);}}]},orderCountDate: '',chartSettings: {xAxisType: 'time',area:true,axisSite: { right: ['orderAmount']},labelMap: {'orderCount': '订单数量', 'orderAmount': '订单金额'}},chartData: {columns: [],rows: []},loading: false,dataEmpty: false,img_home_order,img_home_today_amount,img_home_yesterday_amount}},created(){this.initOrderCountDate();this.getData();},methods:{handleDateChange(){this.getData();},initOrderCountDate(){let start = new Date();start.setFullYear(2018);start.setMonth(10);start.setDate(1);const end = new Date();end.setTime(start.getTime() + 1000 * 60 * 60 * 24 * 7);this.orderCountDate=[start,end];},getData(){setTimeout(() => {this.chartData = {columns: ['date', 'orderCount','orderAmount'],rows: []};for(let i=0;i<DATA_FROM_BACKEND.rows.length;i++){let item=DATA_FROM_BACKEND.rows[i];let currDate=str2Date(item.date);let start=this.orderCountDate[0];let end=this.orderCountDate[1];if(currDate.getTime()>=start.getTime()&&currDate.getTime()<=end.getTime()){this.chartData.rows.push(item);}}this.dataEmpty = false;this.loading = false}, 1000)}}}
</script><style scoped>.app-container {margin-top: 40px;margin-left: 120px;margin-right: 120px;}.address-layout {}.total-layout {margin-top: 20px;}.total-frame {border: 1px solid #DCDFE6;padding: 20px;height: 100px;}.total-icon {color: #409EFF;width: 60px;height: 60px;}.total-title {position: relative;font-size: 16px;color: #909399;left: 70px;top: -50px;}.total-value {position: relative;font-size: 18px;color: #606266;left: 70px;top: -40px;}.un-handle-layout {margin-top: 20px;border: 1px solid #DCDFE6;}.layout-title {color: #606266;padding: 15px 20px;background: #F2F6FC;font-weight: bold;}.un-handle-content {padding: 20px 40px;}.un-handle-item {border-bottom: 1px solid #EBEEF5;padding: 10px;}.overview-layout {margin-top: 20px;}.overview-item-value {font-size: 24px;text-align: center;}.overview-item-title {margin-top: 10px;text-align: center;}.out-border {border: 1px solid #DCDFE6;}.statistics-layout {margin-top: 20px;border: 1px solid #DCDFE6;}.mine-layout {position: absolute;right: 140px;top: 107px;width: 250px;height: 235px;}.address-content{padding: 20px;font-size: 18px}
</style>

首先我们关注布局,先忽略样式,主要是template这块
在这里插入图片描述
一共有6个部分,分别对应如下图
在这里插入图片描述
那我们便会存在疑问,他的侧边栏和上方导航栏是在哪呢?
在这里插入图片描述
ps:
chrome浏览器长截图方法:
f12->crtl+shift+p(windows)->capture full size即可

这里有个图表,使用的是v-charts技术:
v-charts
vue中使用v-charts

这里就用到组件了:

我们首先看下它的路由是如何配置的:

import Vue from 'vue'
import Router from 'vue-router'Vue.use(Router)/* Layout */
import Layout from '../views/layout/Layout'export const constantRouterMap = [{path: '/login', component: () => import('@/views/login/index'), hidden: true},{path: '/404', component: () => import('@/views/404'), hidden: true},{path: '',component: Layout,redirect: '/home',children: [{path: 'home',name: 'home',component: () => import('@/views/home/index'),meta: {title: '首页', icon: 'home'}}]}...{path: '*', redirect: '/404', hidden: true}
]export default new Router({// mode: 'history', //后端支持可开scrollBehavior: () => ({y: 0}),routes: constantRouterMap
})

我们发现在home里面注册了一个叫Layout的组件

/* Layout */
import Layout from '../views/layout/Layout'
{path: '',component: Layout,redirect: '/home',children: [{path: 'home',name: 'home',component: () => import('@/views/home/index'),meta: {title: '首页', icon: 'home'}}]}

Layout.vue:

<template><div class="app-wrapper" :class="classObj"><sidebar class="sidebar-container"></sidebar><div class="main-container"><navbar></navbar><app-main></app-main></div></div>
</template><script>
import { Navbar, Sidebar, AppMain } from './components'
import ResizeMixin from './mixin/ResizeHandler'export default {name: 'layout',components: {Navbar,Sidebar,AppMain},mixins: [ResizeMixin],computed: {sidebar() {return this.$store.state.app.sidebar},device() {return this.$store.state.app.device},classObj() {return {hideSidebar: !this.sidebar.opened,withoutAnimation: this.sidebar.withoutAnimation,mobile: this.device === 'mobile'}}}
}
</script><style rel="stylesheet/scss" lang="scss" scoped>@import "src/styles/mixin.scss";.app-wrapper {@include clearfix;position: relative;height: 100%;width: 100%;}
</style>

Layout组件实现了将页面合理布局的功能,实现了将页面划分为如下:

  • 侧边栏
  • 主体
    • 导航栏
    • 主体

同时这里的Layout也使用了组件

import { Navbar, Sidebar, AppMain } from './components'

这里我主要分析下Sidebar组件的实现,就是侧边栏的实现

Sidebar>index.vue:

<template><scroll-bar><el-menumode="vertical":show-timeout="200":default-active="$route.path":collapse="isCollapse"background-color="#304156"text-color="#bfcbd9"active-text-color="#409EFF"><sidebar-item :routes="routes"></sidebar-item></el-menu></scroll-bar>
</template><script>
import { mapGetters } from 'vuex'
import SidebarItem from './SidebarItem'
import ScrollBar from '@/components/ScrollBar'export default {components: { SidebarItem, ScrollBar },computed: {...mapGetters(['sidebar']),routes() {return this.$router.options.routes},isCollapse() {return !this.sidebar.opened}}
}
</script>
  1. 这里用了 vuex,具体讲解如下:
    Vuex入门(2)—— state,mapState,…mapState对象展开符详解

  2. SidebarItem.vue:

<template><div class="menu-wrapper"><template v-for="item in routes" v-if="!item.hidden&&item.children"><router-link v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" :to="item.path+'/'+item.children[0].path":key="item.children[0].name"><el-menu-item :index="item.path+'/'+item.children[0].path" :class="{'submenu-title-noDropdown':!isNest}"><svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon><span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{item.children[0].meta.title}}</span></el-menu-item></router-link><el-submenu v-else :index="item.name||item.path" :key="item.name"><template slot="title"><svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon><span v-if="item.meta&&item.meta.title" slot="title">{{item.meta.title}}</span></template><template v-for="child in item.children" v-if="!child.hidden"><sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item><router-link v-else :to="item.path+'/'+child.path" :key="child.name"><el-menu-item :index="item.path+'/'+child.path"><svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon><span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span></el-menu-item></router-link></template></el-submenu></template></div>
</template><script>
export default {name: 'SidebarItem',props: {routes: {type: Array},isNest: {type: Boolean,default: false}},methods: {hasOneShowingChildren(children) {const showingChildren = children.filter(item => {return !item.hidden})if (showingChildren.length === 1) {return true}return false}}
}
</script>

看代码的主要意思就是,在for循环下,一级菜单的就如此显示:

 <router-link v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" :to="item.path+'/'+item.children[0].path":key="item.children[0].name"><el-menu-item :index="item.path+'/'+item.children[0].path" :class="{'submenu-title-noDropdown':!isNest}"><svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon><span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{item.children[0].meta.title}}</span></el-menu-item></router-link>

二级菜单的就是:

<el-submenu v-else :index="item.name||item.path" :key="item.name"><template slot="title"><svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon><span v-if="item.meta&&item.meta.title" slot="title">{{item.meta.title}}</span></template><template v-for="child in item.children" v-if="!child.hidden"><sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item><router-link v-else :to="item.path+'/'+child.path" :key="child.name"><el-menu-item :index="item.path+'/'+child.path"><svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon><span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span></el-menu-item></router-link></template></el-submenu>
  1. ScrollBar
    就是为了实现侧边栏的滚动
<template><div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll" ><div class="scroll-wrapper" ref="scrollWrapper" :style="{top: top + 'px'}"><slot></slot></div></div>
</template><script>
const delta = 15export default {name: 'scrollBar',data() {return {top: 0}},methods: {handleScroll(e) {const eventDelta = e.wheelDelta || -e.deltaY * 3const $container = this.$refs.scrollContainerconst $containerHeight = $container.offsetHeightconst $wrapper = this.$refs.scrollWrapperconst $wrapperHeight = $wrapper.offsetHeightif (eventDelta > 0) {this.top = Math.min(0, this.top + eventDelta)} else {if ($containerHeight - delta < $wrapperHeight) {if (this.top < -($wrapperHeight - $containerHeight + delta)) {this.top = this.top} else {this.top = Math.max(this.top + eventDelta, $containerHeight - $wrapperHeight - delta)}} else {this.top = 0}}}}
}
</script><style rel="stylesheet/scss" lang="scss" scoped>
@import '../../styles/variables.scss';.scroll-container {position: relative;width: 100%;height: 100%;background-color: $menuBg;.scroll-wrapper {position: absolute;width: 100%!important;}
}
</style>

最后,这里我们再来看下什么是svg-icon

<svg-icon :icon-class="item.meta.icon"></svg-icon>

svg-sprite-loader 使用教程
懒人神器:svg-sprite-loader实现自己的Icon组件

脚手架中的配置:

vue-cli3中使用svg-sprite-loader方法

这篇关于mall-admin web前端分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/779260

相关文章

Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)

《Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)》文章介绍了如何使用dhtmlx-gantt组件来实现公司的甘特图需求,并提供了一个简单的Vue组件示例,文章还分享了一... 目录一、首先 npm 安装插件二、创建一个vue组件三、业务页面内 引用自定义组件:四、dhtmlx

Vue ElementUI中Upload组件批量上传的实现代码

《VueElementUI中Upload组件批量上传的实现代码》ElementUI中Upload组件批量上传通过获取upload组件的DOM、文件、上传地址和数据,封装uploadFiles方法,使... ElementUI中Upload组件如何批量上传首先就是upload组件 <el-upl

前端知识点之Javascript选择输入框confirm用法

《前端知识点之Javascript选择输入框confirm用法》:本文主要介绍JavaScript中的confirm方法的基本用法、功能特点、注意事项及常见用途,文中通过代码介绍的非常详细,对大家... 目录1. 基本用法2. 功能特点①阻塞行为:confirm 对话框会阻塞脚本的执行,直到用户作出选择。②

如何使用CSS3实现波浪式图片墙

《如何使用CSS3实现波浪式图片墙》:本文主要介绍了如何使用CSS3的transform属性和动画技巧实现波浪式图片墙,通过设置图片的垂直偏移量,并使用动画使其周期性地改变位置,可以创建出动态且具有波浪效果的图片墙,同时,还强调了响应式设计的重要性,以确保图片墙在不同设备上都能良好显示,详细内容请阅读本文,希望能对你有所帮助...

CSS3 最强二维布局系统之Grid 网格布局

《CSS3最强二维布局系统之Grid网格布局》CS3的Grid网格布局是目前最强的二维布局系统,可以同时对列和行进行处理,将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,本文介... 深入学习 css3 目前最强大的布局系统 Grid 网格布局Grid 网格布局的基本认识Grid 网

HTML5中下拉框<select>标签的属性和样式详解

《HTML5中下拉框<select>标签的属性和样式详解》在HTML5中,下拉框(select标签)作为表单的重要组成部分,为用户提供了一个从预定义选项中选择值的方式,本文将深入探讨select标签的... 在html5中,下拉框(<select>标签)作为表单的重要组成部分,为用户提供了一个从预定义选项中

前端 CSS 动态设置样式::class、:style 等技巧(推荐)

《前端CSS动态设置样式::class、:style等技巧(推荐)》:本文主要介绍了Vue.js中动态绑定类名和内联样式的两种方法:对象语法和数组语法,通过对象语法,可以根据条件动态切换类名或样式;通过数组语法,可以同时绑定多个类名或样式,此外,还可以结合计算属性来生成复杂的类名或样式对象,详细内容请阅读本文,希望能对你有所帮助...

禁止HTML页面滚动的操作方法

《禁止HTML页面滚动的操作方法》:本文主要介绍了三种禁止HTML页面滚动的方法:通过CSS的overflow属性、使用JavaScript的滚动事件监听器以及使用CSS的position:fixed属性,每种方法都有其适用场景和优缺点,详细内容请阅读本文,希望能对你有所帮助... 在前端开发中,禁止htm

Vue3中的动态组件详解

《Vue3中的动态组件详解》本文介绍了Vue3中的动态组件,通过`component:is=动态组件名或组件对象/component`来实现根据条件动态渲染不同的组件,此外,还提到了使用`markRa... 目录vue3动态组件动态组件的基本使用第一种写法第二种写法性能优化解决方法总结Vue3动态组件动态

spring-boot-starter-thymeleaf加载外部html文件方式

《spring-boot-starter-thymeleaf加载外部html文件方式》本文介绍了在SpringMVC中使用Thymeleaf模板引擎加载外部HTML文件的方法,以及在SpringBoo... 目录1.Thymeleaf介绍2.springboot使用thymeleaf2.1.引入spring