赞
踩
vue3 构建项目是在没阅读官网文档和其他资料的情况下,一边试验一边摸索学习的,如果有不正确的地方,欢迎评论指正~
1、安装 nodeJS
2、安装 vue-cli
npm install -g @vue/cli
# 检测是否安装成功(显示版本号即为安装成功)
vue --version
vue create [项目名]
直接选第一个:
或者选择第三个进行自定义配置:
npm run serve
默认端口是8080
没有自定义安装 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 是将名字作为标签显示,如的写法是
<!-- element-plus -->
<el-icon :size="size" :color="color">
<Edit />
</el-icon>
<!-- elementui -->
<i class="el-icon-edit"></i>
动态引入的写法是在el-icon
标签中添加<component>
标签,并将 icon 名字写在is
属性中:
<!-- <el-icon><icon-menu /></el-icon> -->
<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>
reactive
在控制台打印出来的是proxy
如果是在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)
})
defineProps
不需要导入就可以直接使用
getCurrentInstance
支持访问内部组件实例。getCurrentInstance
只能在 setup
或生命周期钩子
中调用。
ctx.emit("update:paramName", newValue); // 可以向父组件传值
ctx.emit("funcName", paramValue); // 通过调用方法并且向父组件传递参数
但是界面并没有更新,因为vue3
中父组件绑定的值需要用到v-model:xxx
vscode编译器会显示报错:
使用 <script setup>
的组件是默认关闭的,也即通过模板 ref
或者 $parent
链获取到的组件的公开实例,不会暴露任何在 <script setup>
中声明的绑定。
为了在 <script setup>
组件中明确要暴露出去的属性,使用 defineExpose
编译器宏:
<!-- FatherView.vue --> <template> <div> <p>FatherView</p> <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>
<!-- ChildView.vue --> <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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。