zoukankan      html  css  js  c++  java
  • 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;
          }
           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>

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

  • 相关阅读:
    区分jquery中的offset和position
    如何让搜索框的键盘显示搜索按键?
    如何设置table的border-radius?
    如何让输入框自动使用英文输入法?
    如何隐藏数字输入框的上下箭头?
    autocapticalize和autocorrect
    防止注入
    sychronized和lock和区别
    各大公司Java面试题超详细总结
    n的阶乘
  • 原文地址:https://www.cnblogs.com/lhl66/p/13536088.html
Copyright © 2011-2022 走看看