vue3 构建项目是在没阅读官网文档和其他资料的情况下,一边试验一边摸索学习的,如果有不正确的地方,欢迎评论指正~
1、安装 nodeJS
2、安装 vue-cli
npm install -g @vue/cli
# 检测是否安装成功(显示版本号即为安装成功)
vue --version
vue create [项目名]
npm run serve
没有自定义安装 router,需要进行安装:
npm install vue-router@4
main.ts
文件需要引入router
模块
// main.ts
import App from './App.vue';
import router from './router';
createApp(App).use(router).mount("#app");
路由配置写在srt/router
目录下的index.ts
文件中,如果没有这个文件,可以自行创建
// index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import HomeView from '../views/HomeView.vue'
const routes: Array<RouteRecordRaw> = [
{
path: '/', // 路径
name: 'home', // 路由名称
component: HomeView, // 对应的路由页面
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
在src
目录下新增文件夹layout
,新增默认布局文件DefaultLayout.vue
<template>
<div class="layout">
<el-container style="height:100%">
<el-aside class="layout_aside">
<el-menu
:router="true"
:default-active="$route.meta.id"
>
<template v-for="(item, index) in menuList[1].children" :key="index">
<el-menu-item :index="item.meta.id" :route="item" v-if="item.meta.isMenu">
<el-icon><component :is="item.meta.icon">component>el-icon>
<span>{{item.meta.title}}span>
el-menu-item>
template>
el-menu>
el-aside>
<el-container>
<router-view />
el-container>
el-container>
div>
template>
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import {
Document,
Menu as IconMenu,
Location,
Setting,
Expand,
ArrowDown,
SwitchButton,
Fold,
Guide,
Coin,
Connection,
Calendar
} from "@element-plus/icons-vue";
@Options({
components: {
Document,
IconMenu,
Location,
Setting,
Expand,
Fold,
SwitchButton,
ArrowDown,
Guide,
Coin,
Connection,
Calendar
},
})
export default class DefaultLayout extends Vue {
isCollapse: Boolean = true; // 菜单栏是否折叠:false--展开 true--折叠
handleOpen(key: string, keyPath: string[]) {}
handleClose(key: string, keyPath: string[]) {
console.log(key, keyPath);
}
// 折叠/展开菜单栏
collapseHandle(): void {
this.isCollapse = !this.isCollapse;
}
// 菜单栏
get menuList() {return this.$router.options.routes}
// 退出登录
logout():void {
console.log("退出登录");
}
mounted() {
// console.log("路由====", this.menuList, this.$route);
}
}
script>
将布局界面DefaultLayout.vue
作为父组件,其他界面作为该界面的子组件写在children
数组里面
// index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import DefaultLayout from "../layout/DefaultLayout.vue";
const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "DefaultLayout",
component: DefaultLayout,
children: [
{
path: "path",
component: ()=>import("../views/name.vue"),
name: "name",
meta: { // 路由元信息
title: "router-title",
id:"1",
icon: "guide",
}
},
]
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
export default router;
很多时候,系统的菜单都是根据后台配置的,还有权限配置等,菜单前面添加 icon 区分就需要动态引入图标。而 element-plus 是将名字作为标签显示,如的写法是
<el-icon :size="size" :color="color">
<Edit />
el-icon>
<i class="el-icon-edit">i>
动态引入的写法是在el-icon
标签中添加
标签,并将 icon 名字写在is
属性中:
<el-icon><component :is="item.meta.icon">component>el-icon>
要为 JavaScript 对象创建响应式状态,可以使用reactive
方法:
<script setup lang="ts">
import { reactive } from "vue";
let form = reactive({
name: "张三",
age: 11,
gender: "male",
phone: "133******"
})
form.name = "李四"
console.log("form 没变:", form);
let obj = {
name: "东子",
age: 22,
gender: "female",
phone: "122******"
}
form = obj;
console.log("form 后变:", form);
</script>
如果是在script
标签的全局下修改form
的值,界面是可以响应的,但是如果用按钮控制信息的改变,界面是没有变化的:
在方法内form = obj
这种写法是不生效的,需要用到Object.assign(form, obj)
,界面才会更新数据
如果是reactive
需要用到解构,需要用toRefs
let form = reactive({
name: "张三",
age: 11,
gender: "male",
phone: "133******"
})
let { name, age, gender, phone } = form;
name = "李四";
console.log("name:", name);
console.log("age:", age);
console.log("gender:", gender);
console.log("phone:", phone);
import {reactive, toRefs} from 'vue';
let form = reactive({
name: "张三",
age: 11,
gender: "male",
phone: "133******"
})
let { name, age, gender, phone } = toRefs(form);
name.value = "李四";
console.log("name:", name.value);
console.log("age:", age.value);
console.log("gender:", gender.value);
console.log("phone:", phone);
接受一个内部值并返回一个响应式且可变的 ref
对象。ref 对象仅有一个 .value
property,指向该内部值。获取和修改需要通过.value
属性进行:
import {ref} from 'vue';
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
computed
获取的值需要加.value
import { ref, computed } from "vue";
const count = ref(1)
// 只有 get 获取数据
const num = computed(()=>{
return count.value + 1;
})
console.log("num:", num.value); // 2
// get 和 set
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
console.log("plusOne", plusOne.value);
plusOne.value = 1
console.log(count.value) // 0
<template>
<div class="about">
<el-input v-model="state.count">el-input>
div>
template>
import {reactive, watch, ref} from 'vue';
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(newVal, oldVal) => {
console.log("newVal:", newVal)
console.log("oldVal:", oldVal)
},
{
deep: true,
immediate: true
}
)
<template>
<div class="about">
<el-input v-model="count">el-input>
div>
template>
const count = ref(3)
watch(count, (newVal, oldVal) => {
console.log("newVal:", newVal)
console.log("oldVal:", oldVal)
})
getCurrentInstance
支持访问内部组件实例。getCurrentInstance
只能在 setup
或生命周期钩子
中调用。
ctx.emit("update:paramName", newValue); // 可以向父组件传值
ctx.emit("funcName", paramValue); // 通过调用方法并且向父组件传递参数
但是界面并没有更新,因为vue3
中父组件绑定的值需要用到v-model:xxx
vscode编译器会显示报错:
使用 的组件是默认关闭的,也即通过模板
ref
或者 $parent
链获取到的组件的公开实例,不会暴露任何在 中声明的绑定。
为了在 组件中明确要暴露出去的属性,使用
defineExpose
编译器宏:
<template>
<div>
<p>FatherViewp>
<br>
ChildView:
<child-view
ref="childRef"
/>
<el-button @click="clickHandle">获取子组件暴露的值el-button>
<el-button @click="changeHandle">修改子组件暴露的值el-button>
div>
template>
<script lang="ts" setup>
import ChildView from './ChildView.vue';
import { ref } from 'vue';
const childRef = ref('childRef');
// 获取子组件暴露的值
const clickHandle = ()=>{
console.log("childView a:", childRef.value.a);
console.log("childView b:", childRef.value.b);
}
// 修改子组件暴露的值
const changeHandle = ()=>{
childRef.value.a = 33;
childRef.value.b = 3344;
console.log("childView a:", childRef.value.a);
console.log("childView b:", childRef.value.b);
}
script>
<template>
<div>
ChildView
<br>
a:{{a}}
<br>
b:{{b}}
div>
template>
<script lang="ts" setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
script>
<script lang="ts" setup>
import { onMounted, onUpdated, onUnmounted } from 'vue'
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
</script>
npm install axios --save
// 文件目录:utils/request.ts
import axios from "axios";
// 创建axios实例
let service: any = {};
const config = {
timeout: 50000, // 请求超时时间
}
service = axios.create(config);
// request拦截器 axios的一些配置
service.interceptors.request.use(
(config: any) => {
Object.assign(config.data, {
header: {
timeStamp: new Date().getTime().toString()
}
})
return config;
},
(error: any) => {
// Do something with request error
console.error("error:", error); // for debug
Promise.reject(error);
}
);
// respone拦截器 axios的一些配置
service.interceptors.response.use(
(response: any) => {
switch(response.statusText) {
case "OK":
return response.data;
default:
return response;
}
// return response;
},
(error: any) => {
return Promise.reject(error);
}
);
export default service;
// vue.config.ts
const { defineConfig } = require("@vue/cli-service");
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false, // 关闭 eslint 检查
devServer: {
// 多个服务代理
// proxy: {
// "/api": {
// target:"http://xxx.xxx.xxx.xxx", // 代理的后台地址
// pathRewrite: {
// "^/api": "",
// },
// changeOrigin: true,
// ws: true
// }
// },
proxy: "http://xxxxxxx", // 单个服务代理
port: 8011, // 系统前端端口
},
// 配置 @ 路径
chainWebpack: config => {
config.resolve.alias
.set("@", resolve("src"))
.set("assets", resolve("src/assets"))
.set("components", resolve("src/components"))
.set("views", resolve("src/views"))
},
});
npm install vuex@next --save
分模块管理可以将各模块分别写在store/modules
文件夹下,index.ts
进行模块管理
// index.ts
import { createStore } from "vuex";
import module1 from './modules/module1';
import module2 from "./modules/module2";
export default createStore({
state: {
},
getters: {},
mutations: {},
actions: {},
modules: {
module1, // 模块1
module2, // 模块2
},
});
// module1.ts
import api from "@/config/api"; // 接口地址
import service from "@/utils/request"; // axios 封装
const module1 = {
namespaced: true,
state:()=>({
list: []
}),
mutations: {
updateList(state:any, list:string[]) {
state.list = list;
}
},
actions: {
// 调用接口获取数据
async someFunc(content:any,params:Object) {
const res = await service.post(api.xxx, params, {
headers: {
'Content-Type': 'application/json; charset=UTF-8'
}
});
return res;
},
}
}
export default module1;
<script lang="ts" setup>
import { useStore } from "vuex";
const store = useStore();
// 获取 state 的值
let list = store.state.module1.list;
// 更新 state 的 list
store.commit("module1/updateList", [1,2,3]);
// 调用 action 的方法
store.dispatch("module1/someFunc", params)
</script>
element-plus 目前只懂得怎么全局引用,局部引用还在摸索中
npm install element-plus --save
1、在main.ts
引入了element-plus
后会出现下面的报错问题
原本以为是ts
没定义类型,结果是element-plus 版本不对。后面将版本改成2.2.0
就不会报错了
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).use(ElementPlus)mount('#app')
npm run build
1、刷新的时候会显示404:
①在dist
文件夹下新增web.config
文件,然后重启 IIS 即可
// web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Handle History Mode and custom 404/500" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
②或者在 IIS 设置 URL 重定向,效果是一样的
下载 nginx,然后把部署包放到nginx-1.23.0\html
(nginx 下载文件的 html 目录)。
例如新建的目录名是project
找到nginx/config/
目录下的nginx.config
文件
server {
listen 6688; # 你的域名
server_name localhost;
location / {
root html/project; # 部署包放置的位置
index index.html;
try_files $uri $uri/ /index.html;
}
# 后台接口代理设置
location /api/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Credentials true;
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://xxx.com; # 后台接口要代理的地址
index index.html;
}
}
浏览器访问地址就是localhost:6688