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二. 如果在项目中请求数据出现跨域的处理:
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 接口类型 自己手写太麻烦了,可以使用一个线上网址去自动生成
实际截图
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 文件中进行组件注册
- 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>
网友评论