一.安装vue3.0(https://v3.vuejs.org/)
1.首先保证vue cli 的版本,我的版本是@vue/cli 4.5.1 ,如果版本低需要升级一下。升级命令:yarn global add @vue/cli to update
2.创建项目:可以采用界面方式创建(在终端输入vue ui),也可以在命令行创建(在终端输入 vue create dome),注意在创建项目的时候选择3.x版本
3.如果创建项目时你选择的时scss,运行的时候可能会报错:Module build failed (from ./node_modules/sass-loader/dist/cjs.js),意思是找不到sass-loader, 你可以npm rebuild node-sass,然后再运行项目,不出意外就可以运行了。
二.安装 ant design vue 2.0
- npm i --save ant-design-vue@next(Ant Design Vue), 配置按需加载,首先安装插件:npm install babel-plugin-import --save-dev , 在项目根目新建bable.config.js , 在里面输入
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
[
"import",
{ libraryName: "ant-design-vue", libraryDirectory: "es", style: true }
]
],
};
2.我建议新建一个文件来配置需要引入那些组件
在src目录下新建utils文件,在utils文件下新建ant.js,内容如下:
import {
Button,
} from "ant-design-vue";
const ant = {
install(Vue) {
Vue.component(Button.name, Button);
},
};
export default ant;
在main.js 引入ant.js
import ant from "./utils/ant";
createApp(App).use(store).use(router).use(ant).mount('#app')
以上方法是将你用到的ant组件全局引入,一般比较常用的组件,可以这样引用,如果说,某个组件,你只用了一次,你也可以在局部引入,如果你配置了路由的按需加载,这样做会减少首屏的加载速度。局部引入如下:
import Button from "ant-design-vue/lib/button";
在
components: {
Button,
},
3. 安装less-loader, 因为ant 使用的是less,所以需要:
npm install less less-loader --save-dev
配置less-loader :在项目根目录创建vue.cofing.js 输入下面内容:
module.exports = {
css: {
modules: false,
loaderOptions: {
sass: {
},
less: {
lessOptions: {
javascriptEnabled: true,
},
},
},
},
};
4. 测试:在HelloWorld.vue写入(把介绍删了):
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<a-button type="primary">按钮</a-button>
</div>
</template>
你会在页面看到
![d00efb1a140bfc6da54c7ad9d3b8375e.png](https://i-blog.csdnimg.cn/blog_migrate/762805c781f2aac746c6cf51209adc0d.jpeg)
到此vue3.0和ant design vue 2.0的安装和配置就完了
3.Vue3.0和2.x在项目使用中有什么不同?
.我这里要讲的是在使用中,不是介绍两者的原理(我还没有使用vue3.0和ant design vue 2.0做过任何上线项目)
1,2.x使用构造函数new Vue(...)创建实例,3.x使用createApp函数创建实例;
2.x(3.x不能这样用)
import Vue from "vue";
import App from "./App.vue";
import router from "@/router";
import store from "@/store";
// 引入vue ant design
import ant from "./utils/ant";
Vue.use(ant);
new Vue({
router,
store,
render: h => h(App),
}).$mount("#app");
3.x
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
//全局 引入 ant 组件
import ant from "./utils/ant";
createApp(App).use(store).use(router).use(ant).mount('#app')
2. data、methods、computed、watch、props和setup 的比较
在很长一段事件我以为vue3.0不能使用2.x的 data、methods、computed、watch了,后来看到尤大的知乎回答,vue3.0兼容vue2.x的绝大部分api和属性方法,setup的组合式API只是拓展的,你可以用(最好是用),也可以不用。基本上完全兼容
下面我们来比较 一下他们的差别
做一个计数的例子:
(1).声明两个变量:
2.x 在data声明(3.x一样可以用)
data() {
return {
num:1,
obj:{
name:"vue2"
}
},
3.x 使用 reactive处理对象的双向绑定,ref处理js基础类型的双向绑定, 不处理就不是响应式(可以不处理),使用reactive和ref处理过的数据可以在this中访问到,steup没有this,但是vue2.x的方法里有。
先引入ref、reactive
import {ref,reactive,computed} from "vue";
setup(props) {
let numx = ref(1);
const obj = reactive({
objx: {
name: "vue3",
},
});
return {
numx,
...obj,
};
},
(2)该变数值
2.x(3.x一样可以用)
methods: {
add() {
this.num++;
this.numx++;//ref处理过了,methods里可以访问的到
},
},
3.x
setup(props) {
let numx = ref(1);
const obj = reactive({
objx: {
name: "vue3",
},
});
//定义的方法 setup访问不到data定义的数据
const addx = () => {
numx.value++;
};
return {
numx,
...obj,
addx,
};
},
(3)计算数值的变化(computed)
2.x(3.x一样可以用)
computed: {
com() {
return this.num * 2;
},
},
3.x ,需要引入computed传入get 函数和set函数(可以不传)
import {ref,reactive,computed} from "vue";
setup(props) {
let numx = ref(1);
const obj = reactive({
objx: {
name: "vue3",
},
});
let comx = computed({
get: () => {
return numx.value * 2;
},
});
const addx = () => {
numx.value++;
};
return {
numx,
...obj,
addx,
comx,
};
},
(4)观察数组的变化(watch)
2.x(3.x一样可以用)
watch: {
num: {
deep: true, //开启深度监听
immediate: false, //上来就观察计算
handler(a, b) {
this.obj.name = `vue2变化了:${this.num}`;
},
},
},
3.x 还是要先引入watch, 给watch传入两个参数,第一个是传入要观察哪个值,第二个是改触发的函数
watch(
() => numx.value,//这里直接传numx.value不行,传函数可以
() => {
obj.objx.name = `vue3变化了${numx.value}`;
}
);
**值得注意的是filters已经弃用。
3。 Router的使用
import { createRouter,
createWebHistory,
createWebHashHistory
} from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),//hash模式//createWebHistory(process.env.BASE_URL) 历史模式
routes
})
function newFunction() {
localStorage.setItem("router", JSON.stringify(children));
}
export default router
router,基本上没有变,只不过把方法按需引入了,链式路由跳转,之前的一样可以用,但是在setup里面就不能用了,因为setup里面没有this的概念来看一下对比:
2.x(3.x一样可以用)
methods: {
add() {
this.num++;
this.numx++;
this.$router.push("/about");
},
},
3.x 还是要先引入
import {useRouter} from "vue-router";
setup(props) {
const router = useRouter();
const addx = () => {
router.push("/about");
};
return {
numx,
...obj,
addx,
comx,
};
},
4. vuex的使用
vuex还是和之前一样用,在setup 还是要引入
2.x(3.x一样可以用)
created() {
console.log(this.$store.state.open);
this.$store.commit("changOpne", true);
},
3.x
import {useStore} from "vuex";
setup(props) {
const store = useStore();
console.log(store.state.open);
store.commit("changOpne", false);
},
vuex的辅助函数 mapState,mapGetters,mapMutations,mapActions一样可以使用,但是在setup里面我没有实验成功,如果谁知道怎么用,请在评论区赐教!
5.在添加vue全局属性
2.x(vue3.x不能用)
Vue.prototype.$http = () => {}
3.x
app.config.globalProperties.$http = () => {}
6. vue生命周期
官方文档(https://v3.vuejs.org/api/options-lifecycle-hooks.html#beforecreate)
我需要说的是setup 在created和beforeCreate前面执行
4.数据请求axios(axios中文文档|axios中文网)
1.安装npm i -s axios
2.封装axios
在utils新建request.js
import axios from "axios";
let baseURL = "/api/";
const service = axios.create({
baseURL,
timeout: 5000 // request timeout
});
service.interceptors.request.use(
config => {
// 如果有token 就携带tokon
let token = window.localStorage.getItem("accessToken");
if (token) {
config.headers.common.Authorization = token;
}
return config;
},
error => Promise.reject(error)
);
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data;
if (response.status !== 200) {
return Promise.reject(new Error(res.message || "Error"));
} else {在
return res;
}
},
error => {
console.log("err" + error); // for debug
return Promise.reject(error);
}
);
export default service;
在vue.cofing.js配置请求代理:
devServer: {
host: 'localhost',//target host
port: 8080,
open: true,
//proxy:{'/api':{}},代理器中设置/api,项目中请求路径为/api的替换为target
proxy: {
'/api': {
target: "http://123.56.85.24:5000/",//代理地址,这里设置的地址会代替axios中设置的baseURL http://123.56.85.24:5000/
changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
//ws: true, // proxy websockets
pathRewrite: {
'^/api': '/api'
//pathRewrite: {'^/api': '/'} 重写之后url为 http://192.168.1.16:8085/xxxx
//pathRewrite: {'^/api': '/api'} 重写之后url为 http://192.168.1.16:8085/api/xxxx
}
}
}
},
在src目录下,新建接口请求文件夹api,新建test.js文件
import request from "../utils/request.js";
// 文章列表
export function article() {
return request({
url: "/profile ",
method: "get",
});
}
测试接口:
在HelloWorld.vue 引入
import {
article
} from "../api/test.js";
setup(props) {
const getData = async () => {
const data = await article();
console.log(data);
};
getData();
},
打开控制台会看到一个数组,表示接口访问成功。
5.webpack打包优化
目前为止,我们项目的基本配置都完成了,我们打包看一下实际项目有多大在终端输入npm run build
打开dist简介:
![ac9596f944e55f85ef900752a5829adc.png](https://i-blog.csdnimg.cn/blog_migrate/bac01e79dae9766821a46e3fc1e473dc.jpeg)
可以看到包的大小是2.9MB,什么都就这么大了。
我们先看看看优化后的大小
![990d0da047122b4c876da866cd2bea80.png](https://i-blog.csdnimg.cn/blog_migrate/9e13c7c345b9f428f801818035aa2541.jpeg)
优化后是200K。啥也不说了上代码
const CompressionWebpackPlugin = require("compression-webpack-plugin");
const IS_PRODUCTION = process.env.NODE_ENV === "production";
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
const cdn = {
css: [],
js: [
],
};
// const host = window.location.host;
console.log(IS_PRODUCTION);
const externals = {
};
module.exports = {
publicPath: "./",
outputDir: "dist",
assetsDir: "static",
indexPath: "index.html",
productionSourceMap: false, // 关闭sourceMap
devServer: {
host: 'localhost',//target host
port: 8080,
open: true,
//proxy:{'/api':{}},代理器中设置/api,项目中请求路径为/api的替换为target
proxy: {
'/api': {
target: process.env.BASE_URL,//代理地址,这里设置的地址会代替axios中设置的baseURL http://123.56.85.24:5000/
changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
//ws: true, // proxy websockets
pathRewrite: {
'^/api': '/api'
//pathRewrite: {'^/api': '/'} 重写之后url为 http://192.168.1.16:8085/xxxx
//pathRewrite: {'^/api': '/api'} 重写之后url为 http://192.168.1.16:8085/api/xxxx
}
}
}
},
lintOnSave: false,
configureWebpack: {
// Webpack配置
devtool: "none", // webpack内关闭sourceMap
optimization: {
// 优化配置
splitChunks: {
chunks: "all",
cacheGroups: {
// 拆分Vue
vue: {
test: /[/]node_modules[/]vue[/]/,
name: "chunk-vue",
},
},
},
},
resolve: {
alias: {
"@": resolve("src"), // 主目录
"views": resolve("src/views"), // 页面
'components': resolve("src/components"), // 组件
'api': resolve("src/api"), // 接口
'utils': resolve("src/utils"), // 通用功能
'assets': resolve("src/assets"), // 静态资源
'style': resolve("src/style"), // 通用样式
},
},
},
chainWebpack(config) {
if (IS_PRODUCTION) {
config.plugin("html").tap(args => {
args[0].cdn = cdn;
return args;
});
config.externals(externals);
config.plugin("html").tap(args => {
args[0].minify.minifyCSS = true;
return args;
});
// gzip需要nginx进行配合
config
.plugin("compression")
.use(CompressionWebpackPlugin)
.tap(() => [
{
test: /.js$|.html$|.css/, // 匹配文件名
threshold: 10240, // 超过10k进行压缩
deleteOriginalAssets: true, // 是否删除源文件,这里最好不要删除
}
]);
}
},
css: {
// 是否使用css分离插件 ExtractTextPlugin
extract: !!IS_PRODUCTION,
// 开启 CSS source maps?
sourceMap: false,
// css预设器配置项
// 启用 CSS modules for all css / pre-processor files.
modules: false,
loaderOptions: {
sass: {
},
less: {
lessOptions: {
javascriptEnabled: true,
},
},
},
},
};
cdn里面并没有东西,是因为我没有找到最新的vue全家桶的 cdn,如果你有资源,只需要向下面这样写就行:
const cdn = {
css: [],
js: [
"https://cdn.bootcss.com/vue/2.6.10/vue.min.js",
"https://cdn.bootcss.com/vue-router/3.0.3/vue-router.min.js",
"https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js",
"https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js",
],
};
const externals = {
vue: "Vue",
"vue-router": "VueRouter",
vuex: "Vuex",
axios: "axios",
};
开启gzip,服务器一定要配置gzip,我推荐不要删除原来的文件。不删除源文件包的大小大概在800k左右
以上代码地址:huoqingzhu/vue3.0-ant2.0