Vue管理系统前端之组件拆分封装详解


Posted in Javascript onAugust 23, 2020

组件封装

在上一篇记录中,首页中有太多的代码,为了避免代码的臃肿,需要对主要的功能模块拆分,来让代码看起来更简洁,且能进行复用。

拆分后还加了些小功能,加入了修改 title 的代码,修改方式参考vue 动态修改 title。

还增加了当前请求的页面缓存,使用状态管理器处理。监听路由,保存到 state 中,来处理的。 如何监听可参考vue 计算属性和监听属性。

完整效果图如下:

Vue管理系统前端之组件拆分封装详解

首页布局拆分后结构

拆分后的,布局结构图:

Vue管理系统前端之组件拆分封装详解

拆分后代码

布局最外层 index 代码,使用头部,侧边栏,主内容栏组成,代码如下:

<!-- 布局的首页 -->
<template>
 <div>
 <l-header></l-header>
 <l-aside></l-aside>
 <l-main></l-main>
 </div>
</template>
<script>
import LHeader from './components/header'
import LAside from './components/aside'
import LMain from './components/main'
export default {
 data() {
 return {}
 },
 //引入组件
 components: {
 LHeader,
 LAside,
 LMain,
 },
}
</script>
<style lang="scss" scoped></style>

头部 index.vue 代码:

<!-- 头部文件 -->
<template>
 <div class="header">
 <!-- logo -->
 <logo></logo>
 <!-- 折叠按钮 -->
 <hamburger></hamburger>
 <!-- 头部导航栏 -->
 <div class="heardNavBar">
 <el-menu default-active="1" class="el-menu-demo" background-color="#4b5f6e" text-color="#fff" active-text-color="#ffd04b" mode="horizontal">
 <el-menu-item index="1" @click="$router.push('/')">首页</el-menu-item>
 <el-menu-item index="2" @click="openUrl('#')">使用文档</el-menu-item>
 <el-menu-item index="3" @click="openUrl('https://github.com/levy-w-wang/lion-ui')">GitHub</el-menu-item>
 </el-menu>
 </div>
 <!-- 右侧信息 -->
 <div style="float:right">
 <!-- 全屏 -->
 <div style="float:left;line-height: 60px; padding: 0 10px;">
 <i class="el-icon-full-screen" @click="toggleFull"></i>
 </div>
 <!-- 个人信息 -->
 <div class="userinfo">
 <el-dropdown trigger="hover">
  <span class="el-dropdown-link userinfo-inner">
  <img src="@assets/img/user.jpg" />
  {{ $store.getters.userInfo.username }}<i class="el-icon-caret-bottom"></i>
  </span>
  <el-dropdown-menu slot="dropdown">
  <el-dropdown-item>
  <router-link to="/"><i class="el-icon-s-home"></i>首页</router-link>
  </el-dropdown-item>
  <el-dropdown-item>
  <router-link to="/"><i class="el-icon-s-custom"></i>我的主页</router-link>
  </el-dropdown-item>
  <el-dropdown-item divided>
  <a @click="loginOut()"><i class="el-icon-switch-button"></i>登出</a>
  </el-dropdown-item>
  </el-dropdown-menu>
 </el-dropdown>
 </div>
 </div>
 </div>
</template>

<script>
import screenfull from 'screenfull'
import hamburger from './hamburger'
import logo from './logo'
// import { mapState } from 'vuex'
export default {
 data() {
 return {}
 },
 computed: {
 // ...mapState({
 // isCollapse: (state) => state.app.isCollapse,
 // }),
 },
 //引入组件
 components: {
 hamburger,
 logo,
 },
 // 方法
 methods: {
 openUrl(url) {
 window.open(url)
 },
 loginOut() {
 this.$confirm('确认退出吗?', '提示', {
 type: 'warning',
 })
 .then(() => {
  this.$store.commit('logout')
 })
 .catch(() => {})
 },
 toggleFull() {
 if (!screenfull.isEnabled) {
 this.$message({
  type: 'warning',
  message: 'you browser can not work',
 })
 return false
 }
 screenfull.toggle()
 },
 },
 //未挂载DOM,不能访问ref为空数组
 //可在这结束loading,还做一些初始化,实现函数自执行,
 //可以对data数据进行操作,可进行一些请求,请求不易过多,避免白屏时间太长。
 created() {},
 //可在这发起后端请求,拿回数据,配合路由钩子做一些事情;可对DOM 进行操作
 mounted() {},
}
</script>

<style lang="scss" scoped>
.header {
 padding-left: 0px !important;
 height: 60px;
 line-height: 60px;
 width: 100%;
 background: #4b5f6e;
 color: #fff;

 .heardNavBar {
 float: left;
 background: #4b5f6e;
 padding: 0px 0px;
 height: 60px;
 line-height: 60px;
 font-size: 28px;
 cursor: pointer;
 }

 .userinfo {
 text-align: right;
 padding-right: 24px;
 float: right;
 padding: 0 10px;
 .userinfo-inner {
 font-size: 20px;
 cursor: pointer;
 color: #fff;
 img {
 width: 40px;
 height: 40px;
 border-radius: 10px;
 margin: 10px 0px 10px 10px;
 float: right;
 }
 }
 }
}
</style>

头部中引用的相关组件代码如下

折叠导航栏 hamburger 下的 index.vue 代码:

<template>
 <div @click="toggleCollapse">
 <svg :class="{ 'is-active': !isCollapse }" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
 <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
 </svg>
 </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
 name: 'Hamburger',
 computed: {
 ...mapState({
 isCollapse: (state) => state.app.isCollapse,
 }),
 },
 methods: {
 //折叠导航栏
 toggleCollapse: function () {
 this.$store.commit('toggleCollapse')
 },
 },
}
</script>

<style scoped>
.hamburger {
 padding-left: 13px;
 padding-right: 13px;
 text-align: center;
 width: 34px;
 height: 60px;
 line-height: 60px;
 float: left;
 cursor: pointer;
}

.is-active {
 transform: rotate(180deg);
}
</style>

折叠导航栏 logo 下的 index.vue 代码:

<!-- -->
<template>
 <div class="logo" :class="isCollapse ? 'logo-collapse-width' : 'logo-width'">
 <img v-if="isCollapse" src="@assets/logo6065.png" @click="$router.push('/')" />
 <img v-else src="@assets/logo.png" @click="$router.push('/')" />
 </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
 data() {
 return {}
 },
 computed: {
 ...mapState({
 isCollapse: (state) => state.app.isCollapse,
 }),
 },
}
</script>
<style lang="scss" scoped>
.logo {
 float: left;
 height: 60px;
 padding: 0;
 margin: 0;
}
.logo-width {
 width: 230px;
}
.logo-collapse-width {
 width: 65px;
}
</style>

侧边栏下的 index.vue代码:

<!-- aside -->
<template>
 <div class="aside-container" :class="isCollapse ? 'aside-collapse-width' : 'aside-width'">
 <!--导航菜单 default-active="1-1"-->
 <el-menu class="el-menu-vertical-demo" :class="isCollapse ? 'aside-collapse-width' : 'aside-width'" :collapse-transition="false" :unique-opened="true" :collapse="isCollapse">
 <el-submenu index="1">
 <template slot="title">
  <i class="el-icon-setting"></i>
  <span slot="title">系统管理</span>
 </template>
 <el-menu-item index="1-1" @click="$router.push('usermanage')">用户管理</el-menu-item>
 <el-menu-item index="1-2" @click="$router.push('menumanage')">菜单管理</el-menu-item>
 </el-submenu>
 <el-menu-item index="2" disabled>
 <i class="el-icon-magic-stick"></i>
 <span slot="title">导航一</span>
 </el-menu-item>
 <el-menu-item index="3" disabled>
 <i class="el-icon-reading"></i>
 <span slot="title">导航二</span>
 </el-menu-item>
 </el-menu>
 </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
 data() {
 return {}
 },
 //$store.getters.isCollapse
 computed: {
 ...mapState({
 isCollapse: (state) => state.app.isCollapse,
 }),
 mainTabs: {
 get() {
 return this.$store.state.app.mainTabs
 },
 set(val) {
 this.$store.commit('updateMainTabs', val)
 },
 },
 mainTabsActiveName: {
 get() {
 return this.$store.state.app.mainTabsActiveName
 },
 set(val) {
 this.$store.commit('updateMainTabsActiveName', val)
 },
 },
 },
 watch: {
 $route: 'handleRoute',
 },
 created() {
 console.log(this.$route)
 this.handleRoute(this.$route)
 },
 methods: {
 // 路由操作处理
 handleRoute(route) {
 // tab标签页选中, 如果不存在则先添加
 var tab = this.mainTabs.filter((item) => item.name === route.name)[0]
 if (!tab) {
 tab = {
  name: route.name,
  title: route.meta.title,
  icon: route.meta.icon,
 }
 this.mainTabs = this.mainTabs.concat(tab)
 }
 this.mainTabsActiveName = tab.name
 },
 },
}
</script>
<style lang="scss" scoped>
.aside-container {
 position: fixed;
 top: 0px;
 left: 0;
 bottom: 0;
 z-index: 1020;
 .el-menu {
 position: absolute;
 top: 60px;
 bottom: 0px;
 text-align: left;
 }
}
.aside-width {
 width: 230px;
}
.aside-collapse-width {
 width: 65px;
}
</style>

内容模块下的 index.vue代码:

<!-- -->
<template>
 <div class="main-container clear" :class="isCollapse ? 'position-collapse-left' : 'position-left'">
 <!-- 标签页 -->
 <el-tabs class="tabs" :class="isCollapse ? 'position-collapse-left' : 'position-left'" v-model="mainTabsActiveName" :closable="true" type="card" @tab-click="selectedTabHandle" @tab-remove="removeTabHandle">
 <el-dropdown class="tabs-tools" :show-timeout="0" trigger="hover">
 <div style="font-size:20px;width:50px;">
  <i class="el-icon-arrow-down"></i>
 </div>
 <el-dropdown-menu slot="dropdown">
  <el-dropdown-item @click.native="tabsCloseCurrentHandle">关闭当前标签</el-dropdown-item>
  <el-dropdown-item @click.native="tabsCloseOtherHandle">关闭其它标签</el-dropdown-item>
  <el-dropdown-item @click.native="tabsCloseAllHandle">关闭全部标签</el-dropdown-item>
  <el-dropdown-item @click.native="tabsRefreshCurrentHandle">刷新当前标签</el-dropdown-item>
 </el-dropdown-menu>
 </el-dropdown>
 <el-tab-pane v-for="item in mainTabs" :key="item.name" :label="item.title" :name="item.name">
 <span slot="label"> <i :class="item.icon"></i> {{ item.title }} </span>
 </el-tab-pane>
 </el-tabs>

 <!-- 主内容区域 -->
 <div class="main-content">
 <keep-alive>
 <transition name="fade" mode="out-in">
  <router-view></router-view>
 </transition>
 </keep-alive>
 </div>
 </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
 data() {
 return {}
 },
 computed: {
 ...mapState({
 isCollapse: (state) => state.app.isCollapse,
 }),
 mainTabs: {
 get() {
 return this.$store.state.app.mainTabs
 },
 set(val) {
 this.$store.commit('updateMainTabs', val)
 },
 },
 mainTabsActiveName: {
 get() {
 return this.$store.state.app.mainTabsActiveName
 },
 set(val) {
 this.$store.commit('updateMainTabsActiveName', val)
 },
 },
 },
 methods: {
 // tabs, 选中tab
 selectedTabHandle(tab) {
 tab = this.mainTabs.filter((item) => item.name === tab.name)
 if (tab.length >= 1) {
 this.$router.push({ name: tab[0].name })
 }
 },
 // tabs, 删除tab
 removeTabHandle(tabName) {
 // 当只有首页时,不允许关掉。 若是其它页面可关掉后,push 首页进去
 if (this.mainTabs.length == 1 && this.mainTabs[0].name == 'index') {
 return
 }
 this.mainTabs = this.mainTabs.filter((item) => item.name !== tabName)
 if (this.mainTabs.length >= 1) {
 // 当前选中tab被删除
 if (tabName === this.mainTabsActiveName) {
  this.$router.push({ name: this.mainTabs[this.mainTabs.length - 1].name }, () => {
  this.mainTabsActiveName = this.$route.name
  })
 }
 } else {
 this.$router.push('/')
 }
 },
 // tabs, 关闭当前
 tabsCloseCurrentHandle() {
 this.removeTabHandle(this.mainTabsActiveName)
 },
 // tabs, 关闭其它
 tabsCloseOtherHandle() {
 this.mainTabs = this.mainTabs.filter((item) => item.name === this.mainTabsActiveName)
 },
 // tabs, 关闭全部
 tabsCloseAllHandle() {
 this.mainTabs = []
 this.$router.push('/')
 },
 // tabs, 刷新当前
 tabsRefreshCurrentHandle() {
 var tempTabName = this.mainTabsActiveName
 this.removeTabHandle(tempTabName)
 this.$nextTick(() => {
 this.$router.push({ name: tempTabName })
 })
 },
 },
}
</script>
<style lang="scss" scoped>
.main-container {
 padding: 0 5px 5px;
 position: absolute;
 top: 60px;
 left: 1px;
 right: 1px;
 bottom: 0px;
 .tabs {
 position: fixed;
 top: 60px;
 right: 50px;
 padding-left: 0px;
 padding-right: 2px;
 z-index: 1020;
 height: 40px;
 line-height: 40px;
 font-size: 14px;
 background: rgb(255, 253, 255);
 border-color: rgba(200, 206, 206, 0.5);
 // border-left-width: 1px;
 // border-left-style: solid;
 border-bottom-width: 1px;
 border-bottom-style: solid;
 }
 .tabs-tools {
 position: fixed;
 top: 60px;
 right: 0;
 z-index: 1020;
 height: 40px;
 // padding: 0 10px;
 font-size: 14px;
 line-height: 40px;
 cursor: pointer;
 border-color: rgba(200, 206, 206, 0.5);
 border-left-width: 1px;
 border-left-style: solid;
 border-bottom-width: 1px;
 border-bottom-style: solid;
 background: rgba(255, 255, 255, 1);
 }
 .tabs-tools:hover {
 background: rgba(200, 206, 206, 1);
 }
 .main-content {
 position: absolute;
 top: 45px;
 left: 5px;
 right: 5px;
 bottom: 5px;
 padding: 5px;
 // background: rgba(209, 212, 212, 0.5);
 }
}
.position-left {
 left: 230px;
}
.position-collapse-left {
 left: 65px;
}
</style>

状态管理中添加 app 模块

代码如下:

export default {
 state: {
 // 是否折叠导航栏
 isCollapse: false,
 // 访问页集合
 mainTabs: [],
 // 当前访问页名
 mainTabsActiveName: '',
 },
 getters: {
 isCollapse: (state) => {
 return state.isCollapse
 },
 },
 mutations: {
 toggleCollapse(state) {
 state.isCollapse = !state.isCollapse
 },
 updateMainTabs(state, tabs) {
 state.mainTabs = tabs
 },
 updateMainTabsActiveName(state, name) {
 state.mainTabsActiveName = name
 },
 },
 actions: {},
}

当然还有一些小的调整点,可参考 git 上的提交版本 首页组件拆分

总结

到此这篇关于Vue管理系统前端之组件拆分封装的文章就介绍到这了,更多相关Vue组件拆分封装内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js模拟滚动条(横向竖向)
Feb 22 Javascript
jquery异步跨域访问代码
Jun 28 Javascript
jquery序列化form表单使用ajax提交后处理返回的json数据
Mar 03 Javascript
《JavaScript高级编程》学习笔记之object和array引用类型
Nov 01 Javascript
SpringMVC返回json数据的三种方式
Dec 10 Javascript
浅谈JavaScript中的分支结构
Jul 01 Javascript
JS实现n秒后自动跳转的两种方法
Nov 30 Javascript
Bootstrap 布局组件(全)
Jul 18 Javascript
各式各样的导航条效果css3结合jquery代码实现
Sep 17 Javascript
小程序分享链接onShareAppMessage的具体用法
May 22 Javascript
JS中的变量作用域(console版)
Jul 18 Javascript
JS的时间格式化和时间戳转换函数示例详解
Jul 27 Javascript
Vue中keep-alive组件的深入理解
Aug 23 #Javascript
google广告之另类js调用实现代码
Aug 22 #Javascript
JS typeof fn === 'function' &amp;&amp; fn()详解
Aug 22 #Javascript
js+canvas实现图片格式webp/png/jpeg在线转换
Aug 22 #Javascript
JavaScript中的函数式编程详解
Aug 22 #Javascript
微信小程序中data-key属性之数据传输(经验总结)
Aug 22 #Javascript
Vue 电商后台管理项目阶段性总结(推荐)
Aug 22 #Javascript
You might like
PHP设计模式之责任链模式的深入解析
2013/06/13 PHP
php实现阿拉伯数字和罗马数字相互转换的方法
2015/04/17 PHP
jQuery实战之仿淘宝商城左侧导航效果
2011/04/12 Javascript
jquery获取tagName再进行判断
2014/05/29 Javascript
深入理解javascript变量声明
2014/11/20 Javascript
实例详解Nodejs 保存 payload 发送过来的文件
2016/01/14 NodeJs
bootstrap fileinput 上传插件的基础使用
2017/02/17 Javascript
微信小程序 开发MAP(地图)实例详解
2017/06/27 Javascript
详解ES6之async+await 同步/异步方案
2017/09/19 Javascript
Vue之Vue.set动态新增对象属性方法
2018/02/23 Javascript
解决微信小程序中转换时间格式IOS不兼容的问题
2019/02/15 Javascript
浅谈Vuex注入Vue生命周期的过程
2019/05/20 Javascript
jquery.pager.js实现分页效果
2019/07/29 jQuery
Pyhton中防止SQL注入的方法
2015/02/05 Python
Python字符串详细介绍
2015/05/09 Python
python清除字符串前后空格函数的方法
2018/10/21 Python
Linux 修改Python命令的方法示例
2018/12/03 Python
Python chardet库识别编码原理解析
2020/02/18 Python
keras中模型训练class_weight,sample_weight区别说明
2020/05/23 Python
python判断是空的实例分享
2020/07/06 Python
python3中编码获取网页的实例方法
2020/11/16 Python
python 如何引入协程和原理分析
2020/11/30 Python
python UIAutomator2使用超详细教程
2021/02/19 Python
阿里巴巴国际站:Alibaba.com
2016/07/21 全球购物
Myprotein丹麦官网:欧洲第一运动营养品牌
2019/04/15 全球购物
英国现代家具和照明购物网站:Heal’s
2019/10/30 全球购物
shell程序中如何注释
2012/02/17 面试题
计算机专业毕业生求职信分享
2013/12/24 职场文书
幼儿园消防安全制度
2014/01/26 职场文书
双十佳事迹材料
2014/01/29 职场文书
2014年学习厉行节约反对浪费思想汇报
2014/09/10 职场文书
业务员工作态度散漫检讨书
2014/11/02 职场文书
总经理司机岗位职责
2015/04/10 职场文书
2016关于学习党章的心得体会
2016/01/15 职场文书
浙江省杭州市平均工资标准是多少?
2019/07/09 职场文书
Python max函数中key的用法及原理解析
2021/06/26 Python