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 相关文章推荐
javascript 遍历验证所有文本框的值
Aug 27 Javascript
发布一个基于javascript的动画类 Fx.js
Nov 05 Javascript
js返回上一页并刷新代码整理
Dec 21 Javascript
extjs两个tbar问题探讨
Aug 08 Javascript
jQuery实现将页面上HTML标签换成另外标签的方法
Jun 09 Javascript
JS代码防止SQL注入的方法(超简单)
Apr 12 Javascript
jquery自适应布局的简单实例
May 28 Javascript
jQuery查找dom的几种方法效率详解
May 17 jQuery
js定义类的方法示例【ES5与ES6】
Jul 30 Javascript
ES6 新增的创建数组的方法(小结)
Aug 01 Javascript
Vue2.X和Vue3.0数据响应原理变化的区别
Nov 07 Javascript
javascript 代码是如何被压缩的示例代码
May 06 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数组实现无限分类,不使用数据库,不使用递归.
2006/12/09 PHP
PHP用身份证号获取星座和生肖的方法
2013/11/07 PHP
jQuery+PHP发布的内容进行无刷新分页(Fckeditor)
2015/10/22 PHP
phpstorm 配置xdebug的示例代码
2019/03/31 PHP
PHP+Redis链表解决高并发下商品超卖问题(实现原理及步骤)
2020/08/03 PHP
实用的JS正则表达式(手机号码/IP正则/邮编正则/电话等)
2013/01/11 Javascript
js实现的折叠导航示例
2013/11/29 Javascript
jquery新的绑定事件机制on方法的使用方法
2014/04/15 Javascript
js实现发送验证码后的倒计时功能
2015/05/28 Javascript
微信小程序 chooseImage选择图片或者拍照
2017/04/07 Javascript
微信小程序之获取当前位置经纬度以及地图显示详解
2017/05/09 Javascript
AngularJS自定义指令实现面包屑功能完整实例
2017/05/17 Javascript
判断jQuery是否加载完成,没完成继续判断的解决方法
2017/12/06 jQuery
详解node.js 下载图片的 2 种方式
2018/03/02 Javascript
js构建二叉树进行数值数组的去重与优化详解
2018/03/26 Javascript
Vuex 快速入门(简单易懂)
2018/09/20 Javascript
详解vue 2.6 中 slot 的新用法
2019/07/09 Javascript
[03:55]DOTA2完美大师赛选手传记——LFY.MONET
2017/11/18 DOTA
跟老齐学Python之print详解
2014/09/28 Python
获取django框架orm query执行的sql语句实现方法分析
2019/06/20 Python
利用python实现短信和电话提醒功能的例子
2019/08/08 Python
关于PyTorch 自动求导机制详解
2019/08/18 Python
对pytorch中的梯度更新方法详解
2019/08/20 Python
Django框架创建项目的方法入门教程
2019/11/04 Python
python subprocess pipe 实时输出日志的操作
2020/12/05 Python
BeautifulSoup获取指定class样式的div的实现
2020/12/07 Python
实例教程 HTML5 Canvas 超炫酷烟花绽放动画实现代码
2014/11/05 HTML / CSS
加拿大票务网站:Ticketmaster加拿大
2017/07/17 全球购物
全球性的女装店:storets
2019/06/12 全球购物
介绍一下Linux内核的排队自旋锁
2014/01/04 面试题
业务部门经理岗位职责
2014/02/23 职场文书
高中军训感言800字
2014/03/05 职场文书
幼儿园父亲节活动方案
2014/03/11 职场文书
2015年高三班主任工作总结
2015/05/21 职场文书
幼儿园大班教育随笔
2015/08/14 职场文书
JavaScript中10个Reduce常用场景技巧
2022/06/21 Javascript