美文网首页react & vue & angular
Vue3.0 项目中遇到的问题(十三)

Vue3.0 项目中遇到的问题(十三)

作者: coderhzc | 来源:发表于2022-08-23 21:09 被阅读0次

    0. Vue.config.js 文件配置

    /**
     * vue.config.js
     */
    const path = require("path");
    const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
    const CopyWebpackPlugin = require("copy-webpack-plugin");
    const CompressionPlugin = require("compression-webpack-plugin");
    module.exports = {
      assetsDir: "static", // 打包静态资源目录
      publicPath: "/", // 部署项目的基本URL,默认基于根路径
      outputDir: "dist", //打包文件输出的目录
      productionSourceMap: false, //是否生成map文件
      // webpack相关配置
      configureWebpack: config => {
    
        if (process.env.NODE_ENV === "production") {
          // 为生产环境修改配置...
          config.mode = "production";
          // 代码压缩(需安装uglifyjs-webpack-plugin)
          config.plugins.push(
            new CompressionPlugin(),
            new CopyWebpackPlugin([
              {
                from:
                  "node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml"
              },
              {
                from:
                  "node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf"
              },
              {
                from:
                  "node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js",
                to: "js/"
              }
            ]),
            new UglifyJsPlugin({
              uglifyOptions: {
                //生产环境自动删除console
                compress: {
                  drop_debugger: true,
                  drop_console: true,
                  pure_funcs: ["console.log"]
                }
              },
              sourceMap: false,
              parallel: true //使用多进程并行运行来提高构建速度
            })
          );
        } else {
          // 为开发环境修改配置...
          config.mode = "development";
        }
      },
      // eslint-disable-next-line no-dupe-keys
      configureWebpack: {
        externals: {
          AMap: "AMap" //高德地图
        }
      },
      // chainWebpack链式调用
      chainWebpack: config => {
        config.plugin("html").tap(args => {
          args[0].title = "武昌水务视频管控平台"; // 网站标题
          return args;
        });
        //添加别名
        config.resolve.alias
          .set("@", path.resolve(__dirname, "./src"))
          .set("@assets", path.resolve(__dirname, "./src/assets"))
          .set("@components", path.resolve(__dirname, "./src/components"))
          .set("@views", path.resolve(__dirname, "./src/views"))
          .set("@services", path.resolve(__dirname, "./src/services"))
          .set("@common", path.resolve(__dirname, "./src/common"));
      },
      devServer: {
        open: true, //启动服务自动打开浏览器
        // 配置反向代理
        proxy: {
          "/api": {
            target: "http://180.76.244.24:5000/api/",
            changeOrigin: true,
            pathRewrite: {
              "^/api": ""
            }
          }
        }
      }
    };
    
    

    一. element-plus 中的el-tabs的使用

    image.png
    <el-tabs type="border-card" stretch v-model="currentTab">
          <el-tab-pane>
            <template #label>
              <span class="custom-tabs-label">
                <span>账号登录</span>
              </span>
            </template>
            <login-account ref="accountRef"/>
          </el-tab-pane>
          <el-tab-pane>
            <template #label>
              <span class="custom-tabs-label">
                <span>手机登录</span>
              </span>
            </template>
            <login-phone />
          </el-tab-pane>
        </el-tabs>
    

    实际截图:

    image.png image.png

    el-tabs地址链接

    二. 如果在项目中请求数据出现跨域的处理:

    1. 在vue.config.js 文件中配置代理
    const { defineConfig } = require("@vue/cli-service");
    module.exports = defineConfig({
      transpileDependencies: true,
      outputDir: "./build",
      devServer: {
        proxy: {
          "^/api": {
            target: "http://152.136.185.210:5000",
            pathRewrite: {
              "^/api": "",
            },
            changeOrigin: true,
          },
        },
      },
      configureWebpack: {
        resolve: {
          alias: {
            components: "@/components",
          },
        },
      },
      // publicPath: "./",
      // chainWebpack: (config) => {
      //   config.resolve.alias
      //      .set("@", path.resolve(__dirname, "src"))
      //      .set("components","@/components")
      // },
    });
    
    2. 在你配置的公共路径中需要将配置的地址改一下
    let BASE_URL = ""
    let TIME_OUT = 1000
    /**
     * process.env.NODE_ENV: 他是会通过webpack 的DefinePlugin来自动的通过不同环境来注入值的
     * 当process.env.NODE_ENV 在开发环境时候的值是: development
     * 当process.env.NODE_ENV 在生产环境时候的值是: production
     * 当process.env.NODE_ENV 在测试环境时候的值是: test
     * 
     * **/
    console.log(process.env.NODE_ENV);
    // 上面知道了 process.env.NODE_ENV 在什么环境下是什么值的话下面就很好处理了
    if (process.env.NODE_ENV === "development") {
      BASE_URL = "/api"; // 开发环境
    } else if (process.env.NODE_ENV === "production") {
      BASE_URL = "/prod"; // 线上正式环境
    } else {
      BASE_URL = "/test"; // 测试环境
    }
    // 然后导出 定义的BASE_URL,BASE_NAME
    export {
      BASE_URL,
      TIME_OUT
    }
    

    实际截图

    image.png

    三.定义TS 接口类型 自己手写太麻烦了,可以使用一个线上网址去自动生成

    json2ts地址链接

    实际截图

    image.png

    四.如何修改项目浏览器中的文字和图标

    image.png

    五. 当咱们在点击登录按钮的时候 请求的数据我们都保存在本地浏览器的存储里面的,但是如果一刷新的话,保存在Vuex中的数据会消失,因为VueX是一个响应式的,所以如何处理这个问题呢?

    image.png

    解决方案:

    image.png

    六 如何搭建一个后台管理系统的界面呢?

    如何搭建一个这样的后台管理系统呢? 其实element-plus有提供内置组件的


    image.png

    布局内置组件地址

    1. 先在src/views/main/mian.vue

    <template>
      <div class="main">
        <el-container class="main-content">
          <el-aside :width="isCollapse ? '60px' : '210px'">
            <nav-menu :collapse="isCollapse" />
          </el-aside>
          <el-container class="page">
            <el-header class="page-header">
              <nav-header @foldChange="handleFoldChange" />
            </el-header>
            <el-main class="page-content">Main</el-main>
          </el-container>
        </el-container>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, ref } from 'vue'
    import NavMenu from '@/components/nav-menu'
    import NavHeader from '@/components/nav-header'
    
    export default defineComponent({
      components: {
        NavMenu,
        NavHeader
      },
      setup() {
        const isCollapse = ref(false)
        const handleFoldChange = (isFold: boolean) => {
          isCollapse.value = isFold
        }
    
        return {
          isCollapse,
          handleFoldChange
        }
      }
    })
    </script>
    
    <style scoped lang="less">
    .main {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
    
    .main-content,
    .page {
      height: 100%;
    }
    
    .page-content {
      height: calc(100% - 48px);
    }
    
    .el-header,
    .el-footer {
      display: flex;
      color: #333;
      text-align: center;
      align-items: center;
    }
    
    .el-header {
      height: 48px !important;
    }
    
    .el-aside {
      overflow-x: hidden;
      overflow-y: auto;
      line-height: 200px;
      text-align: left;
      cursor: pointer;
      background-color: #001529;
      transition: width 0.3s linear;
      scrollbar-width: none; /* firefox */
      -ms-overflow-style: none; /* IE 10+ */
    
      &::-webkit-scrollbar {
        display: none;
      }
    }
    
    .el-main {
      color: #333;
      text-align: center;
      background-color: #f0f2f5;
    }
    </style>
    

    2. components/NavMenu/src/NavMenu.vue 这个是main.vue 中的子组件

    components/NavMenu/src/NavMenu.vue: 在components文件里面创建NavMenu文件夹,NavMenu里面放入src文件夹,src文件夹里面放入NavMenu.vue文件

    <template>
      <div class="nav-header">
        <i
          class="fold-menu"
          :class="isFold ? 'el-icon-s-fold' : 'el-icon-s-unfold'"
          @click="handleFoldClick"
        ></i>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, ref } from 'vue'
    
    export default defineComponent({
      emits: ['foldChange'],
      setup(props, { emit }) {
        const isFold = ref(false)
        const handleFoldClick = () => {
          isFold.value = !isFold.value
          emit('foldChange', isFold.value)
        }
    
        return {
          isFold,
          handleFoldClick
        }
      }
    })
    </script>
    
    <style scoped lang="less">
    .nav-header {
      .fold-menu {
        font-size: 30px;
        cursor: pointer;
      }
    }
    </style>
    

    2.1 components/NavMenu/index.ts文件 这个是导出NavMenu.vue文件的出口文件

    import NavMenu from "./src/.vue" // 此时是导入文件
    export  default NavMenu;// 此时是导出文件 到mian.vue 文件中进行组件注册 
    
    1. components/NavHeader/src/NavHeader.vue是main.vue 中的子组件

    components/NavHeader/src/NavHeader.vue: 在components文件里面创建NavHeader文件夹,NavHeader里面放入src文件夹,src文件夹里面放入NavHeader.vue文件

    <template>
      <div class="nav-menu">
        <div class="logo">
          <img class="img" src="~@/assets/img/logo.svg" alt="logo" />
          <span v-if="!collapse" class="title">Vue3+TS</span>
        </div>
        <el-menu
          default-active="2"
          class="el-menu-vertical"
          :collapse="collapse"
          background-color="#0c2135"
          text-color="#b7bdc3"
          active-text-color="#0a60bd"
        >
          <template v-for="item in userMenus" :key="item.id">
            <!-- 二级菜单 -->
            <template v-if="item.type === 1">
              <!-- 二级菜单的可以展开的标题 -->
              <el-submenu :index="item.id + ''">
                <template #title>
                  <i v-if="item.icon" :class="item.icon"></i>
                  <span>{{ item.name }}</span>
                </template>
                <!-- 遍历里面的item -->
                <template v-for="subitem in item.children" :key="subitem.id">
                  <el-menu-item :index="subitem.id + ''">
                    <i v-if="subitem.icon" :class="subitem.icon"></i>
                    <span>{{ subitem.name }}</span>
                  </el-menu-item>
                </template>
              </el-submenu>
            </template>
            <!-- 一级菜单 -->
            <template v-else-if="item.type === 2">
              <el-menu-item :index="item.id + ''">
                <i v-if="item.icon" :class="item.icon"></i>
                <span>{{ item.name }}</span>
              </el-menu-item>
            </template>
          </template>
        </el-menu>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, computed } from 'vue'
    import { useStore } from '@/store'
    
    // vuex - typescript  => pinia
    
    export default defineComponent({
      props: {
        collapse: {
          type: Boolean,
          default: false
        }
      },
      setup() {
        const store = useStore()
        const userMenus = computed(() => store.state.login.userMenus)
        return {
          userMenus
        }
      }
    })
    </script>
    
    <style scoped lang="less">
    .nav-menu {
      height: 100%;
      background-color: #001529;
    
      .logo {
        display: flex;
        height: 28px;
        padding: 12px 10px 8px 10px;
        flex-direction: row;
        justify-content: flex-start;
        align-items: center;
    
        .img {
          height: 100%;
          margin: 0 10px;
        }
    
        .title {
          font-size: 16px;
          font-weight: 700;
          color: white;
        }
      }
    
      .el-menu {
        border-right: none;
      }
    
      // 目录
      .el-submenu {
        background-color: #001529 !important;
        // 二级菜单 ( 默认背景 )
        .el-menu-item {
          padding-left: 50px !important;
          background-color: #0c2135 !important;
        }
      }
    
      ::v-deep .el-submenu__title {
        background-color: #001529 !important;
      }
    
      // hover 高亮
      .el-menu-item:hover {
        color: #fff !important; // 菜单
      }
    
      .el-menu-item.is-active {
        color: #fff !important;
        background-color: #0a60bd !important;
      }
    }
    
    .el-menu-vertical:not(.el-menu--collapse) {
      width: 100%;
      height: calc(100% - 48px);
    }
    </style>
    

    3.1 components/NavHeader/index.ts文件 这个是导出NavHeader.vue文件的出口文件

    import NavHeader from "./src/.vue" // 此时是导入文件
    export  default NavHeader;// 此时是导出文件 到mian.vue 文件中进行组件注册
    
    

    实际截图

    image.png

    七. el-aside 中的width属性的使用

    实际截图

    image.png

    八.如果想使用assets中的图片配置别名怎么办呢?

    以前可能总是会使用<img src="../../../assets/img/login.png" />,现在我想使用别名的方式去配置


    image.png

    九. 侧边栏的导航如何写呢? 完整版代码请看 第六条,代码我已经贴到里面了

    element-plus中提供了 一个组件 ---> el-menu,

     <el-menu
          default-active="2"
          class="el-menu-vertical"
          :collapse="collapse"
          background-color="#0c2135"
          text-color="#b7bdc3"
          active-text-color="#0a60bd"
        >
          <template v-for="item in userMenus" :key="item.id">
            <!-- 二级菜单 -->
           <!-- v-if="item.type === 1": 代表是一个可以实现展开的菜单 -->
            <template v-if="item.type === 1">
              <!-- 二级菜单的可以展开的标题 -->
              <el-submenu :index="item.id + ''">
                <template #title>
                  <i v-if="item.icon" :class="item.icon"></i>
                  <span>{{ item.name }}</span>
                </template>
                <!-- 遍历里面的item -->
                <template v-for="subitem in item.children" :key="subitem.id">
                  <el-menu-item :index="subitem.id + ''">
                    <i v-if="subitem.icon" :class="subitem.icon"></i>
                    <span>{{ subitem.name }}</span>
                  </el-menu-item>
                </template>
              </el-submenu>
            </template>
            <!-- 一级菜单 -->
            <template v-else-if="item.type === 2">
              <el-menu-item :index="item.id + ''">
                <i v-if="item.icon" :class="item.icon"></i>
                <span>{{ item.name }}</span>
              </el-menu-item>
            </template>
          </template>
        </el-menu>
    

    el-menu导航菜单地址

    相关文章

      网友评论

        本文标题:Vue3.0 项目中遇到的问题(十三)

        本文链接:https://www.haomeiwen.com/subject/ofnggrtx.html