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 相关文章推荐
利用jquery操作Radio方法小结
Oct 20 Javascript
JavaScript设计模式之装饰者模式介绍
Dec 28 Javascript
Bootstrap实现登录校验表单(带验证码)
Jun 23 Javascript
JavaScript中原型链存在的问题解析
Sep 25 Javascript
JS多物体实现缓冲运动效果示例
Dec 20 Javascript
webpack实现热加载自动刷新的方法
Jul 30 Javascript
webpack开发跨域问题解决办法
Aug 03 Javascript
JavaScript引用类型Function实例详解
Aug 09 Javascript
Vue CLI 3.x 自动部署项目至服务器的方法
Apr 02 Javascript
解决Vue动态加载本地图片问题
Oct 09 Javascript
Node中对非阻塞I/O、事件循环的知识点总结
Jan 05 Javascript
js操作两个json数组合并、去重,以及删除某一项元素
Sep 22 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
Mysql的常用命令
2006/10/09 PHP
解析php curl_setopt 函数的相关应用及介绍
2013/06/17 PHP
浅谈PHP中如何实现Hook机制
2017/11/14 PHP
JavaScript 比较时间大小的代码
2010/04/24 Javascript
JS 图片缩放效果代码
2010/06/09 Javascript
img onload事件绑定各浏览器均可执行
2012/12/19 Javascript
运算符&amp;&amp;的三个不同层次
2013/04/07 Javascript
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
2013/05/17 Javascript
javascript实现数组中的内容随机输出
2015/08/11 Javascript
js漂浮广告实现代码
2015/08/15 Javascript
JS实现的论坛Ajax打分效果完整实例
2015/10/31 Javascript
JavaScript函数的一些注意要点小结及js匿名函数
2015/11/10 Javascript
jquery跟随屏幕滚动效果的实现代码
2016/04/13 Javascript
基于Bootstrap里面的Button dropdown打造自定义select
2016/05/30 Javascript
详解JS对象封装的常用方式
2016/12/30 Javascript
微信小程序 传值取值的几种方法总结
2017/01/16 Javascript
Vue中函数防抖节流的理解及应用实现
2020/04/24 Javascript
Python中死锁的形成示例及死锁情况的防止
2016/06/14 Python
浅谈django的render函数的参数问题
2018/10/16 Python
python实现批量视频分帧、保存视频帧
2019/05/31 Python
对Python中小整数对象池和大整数对象池的使用详解
2019/07/09 Python
Python3常见函数range()用法详解
2019/12/30 Python
Python3 Tensorlfow:增加或者减小矩阵维度的实现
2020/05/22 Python
python 使用elasticsearch 实现翻页的三种方式
2020/07/31 Python
在Python中实现字典反转案例
2020/12/05 Python
一个入门级python爬虫教程详解
2021/01/27 Python
英国最受欢迎的价格比较网站之一:MoneySuperMarket
2018/12/19 全球购物
电大本科自我鉴定
2014/02/05 职场文书
高一新生军训方案
2014/05/12 职场文书
四年级数学上册教学计划
2015/01/20 职场文书
2015年教师师德师风承诺书
2015/04/28 职场文书
硕士毕业答辩开场白
2015/05/27 职场文书
浅谈redis的过期时间设置和过期删除机制
2022/03/18 MySQL
mysql 获取时间方式
2022/03/20 MySQL
高通2023 年将发布高性能PC处理器
2022/04/29 数码科技
Python中的 No Module named ***问题及解决
2022/07/23 Python