vue项目实战:项目布局和公共文件夹的确定


1.布局文件 

<!-- * @Description: 布局容器组件 vue-intro + intro.js 新手引导页功能 home文件 * @Version: 2.0 * @Autor: lhl * @Date: 2020-06-11 17:54:29 * @LastEditors: lhl * @LastEditTime: 2020-08-20 16:54:29 --> 
<!--  -->
<template>
  <div class="layout-box">
    <el-container>
      <el-header>
        <topHeader />
      </el-header>
      <el-container>
        <el-aside width="220px">
          <el-scrollbar class="page-component__scroll">
            <siderBar />
          </el-scrollbar>
        </el-aside>
        <el-main>
          <div class="right-view" ref="rightViewBox">
            <!-- <Breadcrumb ref="bread"/> -->
            <transition name="fade-transform" mode="out-in">
              <keep-alive :include="keepAliveList">
                <router-view></router-view>
              </keep-alive>
            </transition>
          </div>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script>
// router-view 的 key 或者用路由钩子 再或者用监听路由变化 // 场景:由于 Vue 会复用相同组件, 即 /detail/1 => /detail/2 或者 /detail?id=1 => /detail?id=2 这类链接跳转时, 将不在执行created, mounted之类的钩子 // <router-view :key="$route.fullPath"></router-view> // 这样组件的 created 和 mounted 就都会执行
import topHeader from "./topHeader"; import siderBar from "./siderBar"; import Breadcrumb from '../Breadcrumb/index' import { mapActions, mapGetters, mapMutations } from "vuex"; // 引导
import Driver from 'driver.js' // import driver.js
import 'driver.js/dist/driver.min.css' // import driver.js css
import steps from '@/common/steps' export default { components: { topHeader, siderBar, Breadcrumb }, data() { //这里存放数据
    return { keepAliveList: ['baiduMapTest'] // 缓存的组件
 } }, methods: { ...mapMutations(["setContentBoxHeight", "setBtnPermitCode"]), // 系统引导
 guide() { const driver = new Driver() driver.defineSteps(steps) driver.start() }, // 获取按钮code码
 getBtnCodeList(){ this.$http.user.btnList().then(res => { console.log(res) if(res.returnResult === 200){ this.setBtnPermitCode(res.returnData.buttonList) } }) } }, computed:{ ...mapGetters(['getcontentBoxHeight']) }, created() { this.getBtnCodeList() }, mounted() { this.guide(); //第二种方法
      if (window.performance.navigation.type == 1) { console.log("页面被刷新") } else { console.log("首次被加载") } window.addEventListener("resize", () => { if (this.$refs.rightViewBox && this.$refs.rightViewBox.clientHeight) { this.setContentBoxHeight(this.$refs.rightViewBox.clientHeight); // console.log(this.$refs.rightViewBox.clientHeight, "rightViewBox");
 } }) if (this.$refs.rightViewBox.clientHeight) { this.setContentBoxHeight(this.$refs.rightViewBox.clientHeight); } } }; </script>
<style lang='scss' scoped> //@import url(); 引入公共css类 .layout-box { height: 100%; min-width: 1200px; .el-aside { position: absolute; top: 60px; bottom: 0; background: #3db4f8; .el-menu{ border-right: none;
    } } .el-main { position: absolute; left: 220px; right: 0; top: 60px; bottom: 0; padding: 10px; background: #eee; .right-view{ padding: 20px; background: #fff; min-height: 100%;
    } } } </style>
<!-- * @Description: 侧边栏组件 * @Version: 2.0 * @Autor: lhl * @Date: 2020-06-11 17:54:54 * @LastEditors: lhl * @LastEditTime: 2020-07-17 14:22:49 --> 

<!--  -->
<template>
  <div class="sider-content-box">
    <el-menu class="el-menu-vertical-demo" background-color="#3DB4F8" text-color="#fff" active-text-color="#fff" :collapse-transition="false" router >
      <!-- 一级菜单 -->
      <template v-for="(item,index) in menuData">
        <el-submenu v-if="item.children && item.children.length" :index="item.menuUrl" :key="item.menuUrl"
        >
          <template slot="title">
            <i :class="item.icon"></i>
            <span>{{item.name}}</span>
          </template>
          <!-- 二级菜单 -->
          <template v-for="(itemChild,vIndex) in item.children">
            <el-submenu v-if="itemChild.children && itemChild.children.length" :index="itemChild.menuUrl" :key="vIndex"
            >
              <template slot="title">
                <i :class="itemChild.icon"></i>
                <span>{{itemChild.name}}</span>
              </template>
              <!-- 三级菜单 -->
              <el-menu-item v-for="itemChild_Child in itemChild.children" :index="itemChild_Child.menuUrl" :key="itemChild_Child.menuUrl"
              >
                <i :class="itemChild_Child.icon"></i>
                <span slot="title">{{itemChild_Child.name}}</span>
              </el-menu-item>
            </el-submenu>
            <el-menu-item v-else :index="itemChild.menuUrl" :key="itemChild.vIndex">
              <i :class="itemChild.icon"></i>
              <span slot="title">{{itemChild.name}}</span>
            </el-menu-item>
          </template>
        </el-submenu>
        <el-menu-item v-else :index="item.menuUrl" :key="index">
          <i :class="item.icon"></i>
          <span slot="title">{{item.name}}</span>
        </el-menu-item>
      </template>
    </el-menu>
  </div>
</template>

<script> import { menuData } from '@/common/constant' export default { components: {}, data() { //这里存放数据
    return { menuData }; }, computed: {}, watch: {}, methods: {}, created() {}, mounted() {} }; </script>
<style lang='scss' scoped> //@import url(); 引入公共css类 </style>
<!-- * @Description: 头部组件 * @Version: 2.0 * @Autor: lhl * @Date: 2020-06-12 09:12:02 * @LastEditors: lhl * @LastEditTime: 2020-08-04 17:33:36 --> 
<!--  -->
<template>
  <div class="header-content-box">
    <div class="logo" id="logo">
      <img src="@/assets/logo.png" alt />
    </div>
    <div id="title">vue测试管理系统</div>
    <div class="top-info">
      <div class="user-avatar">
        <img src="@/assets/logo.png" alt />
      </div>
      <div class="user-down" id="user">
        <el-dropdown trigger="click" @command="handleCommand">
          <span class="el-dropdown-link"> {{getUserInfo.userName || '默认用户'}} <i class="el-icon-arrow-down el-icon--right"></i>
          </span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item command="baseInfo">基本资料</el-dropdown-item>
            <el-dropdown-item command="changePassword">修改密码</el-dropdown-item>
            <el-dropdown-item divided command="loginOut">退出登录</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </div>
    </div>
    <el-dialog title="用户基本资料" :visible.sync="dialogVisibleInfo" width="50%">
      <div class="user-info">
        <p>id:{{getUserInfo.id}}</p>
        <p>用户名:{{getUserInfo.userName}}</p>
        <p>账号:{{getUserInfo.domainAccount}}</p>
        <p>所在公司:{{getUserInfo.organizationName}}</p>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisibleInfo = false">取 消</el-button>
        <el-button type="primary" @click="dialogVisibleInfo = false">确 定</el-button>
      </span>
    </el-dialog>

    <el-dialog title="修改密码" :visible.sync="dialogVisibleChangePwd" width="50%">
      <el-form ref="ruleForm" :model="ruleForm" :rules="resetRules" class="login-form" label-width="80px" label-position="left"
      >
        <el-form-item label="密码" prop="passwd">
          <el-input type="password" v-model="ruleForm.passwd" placeholder="请输入密码" autocomplete="off" show-password ></el-input>
        </el-form-item>
        <el-form-item label="确认密码" prop="checkPass">
          <el-input type="password" v-model="ruleForm.checkPass" placeholder="请输入确认密码" autocomplete="off" show-password ></el-input>
        </el-form-item>
      </el-form>

      <span slot="footer" class="dialog-footer">
        <el-button @click="resetForm('ruleForm')">取 消</el-button>
        <el-button type="primary" @click="submitForm('ruleForm')">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script> import { mapMutations, mapGetters } from "vuex"; export default { data() { var validatePass = (rule, value, callback) => { if (value === "") { callback(new Error("请输入密码")); } else { if (this.ruleForm.checkPass !== "") { this.$refs.ruleForm.validateField("checkPass"); } callback(); } }; var validatePass2 = (rule, value, callback) => { if (value === "") { callback(new Error("请再次输入密码")); } else if (value !== this.ruleForm.passwd) { callback(new Error("两次输入密码不一致!")); } else { callback(); } }; //这里存放数据
    return { dialogVisibleInfo: false, // 用户信息
 dialogVisibleChangePwd: false, // 修改用户密码
 ruleForm: { passwd: "", checkPass: "", }, resetRules: { passwd: [{ validator: validatePass, trigger: "blur" }], checkPass: [{ validator: validatePass2, trigger: "blur" }], }, }; }, computed: { ...mapGetters(["getUserInfo"]), }, created() {}, methods: { ...mapMutations(["loginOut"]), handleCommand(command) { console.log(command); if (command === "baseInfo") { this.dialogVisibleInfo = true; } else if (command === "changePassword") { this.dialogVisibleChangePwd = true; } else if (command === "loginOut") { this.$confirm("您确定要退出吗?", "退出管理平台", { confirmButtonText: "确定", cancelButtonText: "取消", }) .then(() => { this.loginOut(); this.$router.push(`/login?redirect=${this.$route.fullPath}`);
 }) .catch(() => {}); } }, submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { // 调用重置密码的接口
 alert("重置密码成功!"); this.dialogVisibleChangePwd = false; } else { // console.log("error submit!!");
          return false; } }); }, resetForm(formName) { this.dialogVisibleChangePwd = false; this.$refs[formName].resetFields(); }, }, }; </script>
<style lang='scss' scoped> //@import url(); 引入公共css类 .header-content-box { height: 60px; display: flex; justify-content: space-between; align-items: center; background: url("~@/assets/img/bg.png"); .logo { img { width: 40px; height: 40px;
    } } .top-info { display: flex; justify-content: center; align-items: center; .user-avatar { border-radius: 50%; img { width: 40px; height: 40px; border-radius: 50%;
      } } } } </style>

2.公共样式

// reset.scss @import './transition.scss'; @import './public.scss'; @import './elementreset.scss'; *{ margin: 0; padding: 0; list-style: none;
}
/** 清除内外边距 **/ body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */ dl, dt, dd, ul, ol, li,/* list elements 列表元素 */ pre, /* text formatting elements 文本格式元素 */ form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */ th, td /* table elements 表格元素 */ { margin: 0; padding: 0;
} body,#app{ height: 100%; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
} html{ height:100%;
} body{ height:100%; margin:0px; padding:0px;
} address, cite, dfn, em, var ,i{ font-style: normal; 
}

/* for ie6 */ fieldset, img { border: 0; } 
/* img :让链接里的 img 无边框 */ button, input, select, textarea { font-size: 100%;} 
/* 使得表单元素在 ie 下能继承字体大小 *//* 注:optgroup 无法扶正 */ /** 重置表格元素 **/ table { border-collapse: collapse; border-spacing: 0; } label { font-weight: 700;
} html *{ font-size: 14px; box-sizing: border-box;
} *, *:before, *:after { box-sizing: inherit;
} // a:focus, // a:active { // outline: none; // } // a, // a:focus, // a:hover { // cursor: pointer; // text-decoration: none; // } div:focus { outline: none;
} .fr { float: right;
} .fl { float: left;
} .clearfix { &:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0;
  } } .md{ display: inline-block; vertical-align: middle;
}


/*去掉type为number的箭头*/ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none;
} input[type="number"] { -moz-appearance: textfield;
} // Dialog 对话框居中显示 .dialog-box-center{ text-align: center; &:after { content: ""; display: inline-block; height: 100%; width: 0; vertical-align: middle;
  } .el-dialog{ text-align: left; display: inline-block; margin: 0 !important; vertical-align: middle; min-width: 800px;
  } }
// transition.scss /*fade*/ .fade-enter-active, .fade-leave-active { transition: opacity 0.3s;
} .fade-enter, .fade-leave-active { opacity: 0;
}

/*fade-transform*/ .fade-transform-leave-active, .fade-transform-enter-active { transition: all .8s;
} .fade-transform-enter { opacity: 0; transform: translateX(-30px);
} .fade-transform-leave-to { opacity: 0; transform: translateX(30px);
}
// public.scss .pd10{ padding: 10px;
} .ptb10{ padding: 10px 0;
} .mt10{ margin-top: 10px;
} .md { display: inline-block; vertical-align: middle;
} // 进度条颜色 #nprogress .bar { background: red !important; //自定义颜色 } .flex-column { display: flex; justify-content: center; flex-direction: column;
}


/*滚动条样式*/ .page-component__scroll { height: 100%; .el-scrollbar__wrap { overflow-x: auto;
  } } /*滚动条颜色*/ .scroll-bar-color { .el-scrollbar__thumb { background-color: rgba(118, 118, 119, 0.8);
  } }
// elementreset.scss // 分页样式 .el-pagination { text-align: right; margin-top: 10px;
} // element ui表头换行 .el-table .cell { white-space: pre-line;
} // tooltip样式更改 固定宽高换行显示 .el-tooltip__popper { max-width: 400px; line-height: 180%;
} // 重置表单样式 element ui 下拉、输入、级联、日期 .reset-form { .el-input, .el-select, .el-cascader, .el-range-editor { width: 100% !important;
  } .el-pagination { .el-input { width: 50px !important;
    } .el-select { .el-input { width: 100px !important;
      } width: 100px !important; } } } .el-table { .el-date-editor.el-input, .el-date-editor.el-input__inner { width: 100% !important;
  } } // to fixed https://github.com/ElemeFE/element/issues/2461 // Dialog内select tree等组件在点击箭头时有虚晃 .el-dialog { transform: none; left: 0; position: relative; margin: 0 auto;
} // 当前行选中颜色高亮 .el-table--striped .el-table__body tr.el-table__row--striped.current-row td, .el-table__body tr.current-row>td { background-color: #ffec8b;
} .el-loading-mask { background-color: rgba(0, 0, 0, .3);
} // 菜单样式 /* 非折叠的竖直菜单处理方式和上方的水平菜单一样,只不过需要将horizontal改为vertical Element-UI中,在没有折叠的菜单中,无论是水平还是竖直菜单,子菜单是放在菜单栏所在的div中的, 只是将display属性设置为了none。 而在折叠菜单中,虽然菜单项也是放在页面上,但不在是放在菜单栏所在的div中,而是放在了页面底部的单独div中, 类属性值是el-menu--popup,因为是单独的div,所以在处理弹出菜单时就比较方便,直接处理el-submenu__title 和el-menu-item就可以,而不必区分是几级菜单项(如果不同级别菜单项要分别处理,需要使用“>”等操作分别处理) */
/*处理竖直菜单收齐后的弹出菜单中的子菜单 */ .el-menu--vertical .el-menu--popup .el-submenu__title { height: 40px; line-height: 40px;
} .el-menu--vertical .el-menu--popup .el-menu-item { height: 40px; line-height: 40px;
} .el-menu--vertical .el-menu--popup .el-icon-arrow-right:before { color: #fff;
}

3.面包屑组件

<!-- * @Description: 全局面包屑组件 Breadcrumb/index.vue * @Version: 2.0 * @Autor: lhl * @Date: 2020-08-04 17:51:48 * @LastEditors: lhl * @LastEditTime: 2020-08-20 16:57:07 -->
<template>
  <div class="breadcrumb-box">
    <!-- separator-class="el-icon-arrow-right" 图标分隔符 class -->
    <el-breadcrumb separator="/">
      <el-breadcrumb-item v-for="item in breadList" :to="{path: item.path }" :key="item.name"
      >{{item.meta.title}}</el-breadcrumb-item>
    </el-breadcrumb>
  </div>
</template>

<script> export default { created() { this.getBreadcrumb(); }, data() { return { breadList: [], }; }, watch: { $route() { this.getBreadcrumb(); }, }, methods: { getBreadcrumb() { let matched = this.$route.matched.filter((item) => item.name); // console.log(matched,'matched')
      this.breadList = matched; }, }, }; </script>
<style lang='scss' scoped> //@import url(); 引入公共css类 .breadcrumb-box{ padding: 10px 0; background: #fff; border-bottom: 1px solid #333;
}
</style>

  以上代码本人项目实测!!!真实可靠,请勿随意转载~转载请注明出处~~~谢谢合作!


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM