react & vue & angular

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

2022-08-23  本文已影响0人  coderhzc

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导航菜单地址

上一篇 下一篇

猜你喜欢

热点阅读