本章主要探究vue-cli脚手架的动态路由匹配, 所谓动态路由匹配:就是将不确定的参数进行路由映射到同一个组件上去。

本文要点:

1.推荐vue-cli博主
2.引入第三方js,css文件
3.项目开发前的准备☆
4.vue-cli监听窗口变化事件
5.vue-cli项目前后分离开发生产环境部署☆☆☆

1.推荐vue-cli博主

这个博主的vue-cli的文章写的不错,很详细,推荐阅读—> 阿清そ

2.引入第三方js,css文件

vue-cli不同于之前的单页面的vue,它更倾向于一个项目快速开发,受约束的地方很多,没有以前在HTML页面中引入vue.js自定义开发那般灵活。

  1. 全局引用js,css文件

index.html是主页面,直接在index.html中引入,此时所有的组件中都会加载引用的第三方文件
注意:这时就会存在一个问题,假如有些组件不会使用jQuery,但也会加载出来,十分消耗性能

  • js
1
<script type="text/javascript" src="./static/mui.min.js" ></script>
  • css
1
<link rel="stylesheet" href="static/mui.min.css" />
  1. 局部组件引用js,css文件:在单页面中用import方法导入,只在当前组件内有效(记得要加scoped)
  • css文件
1
2
3
4
5
6
<style scoped>
@import "../assets/css/DPlayer.min.css";
h3{
text-align: center;
}
</style>
  • js文件

某些第三方的js库会导出一些对象或方法给其它js调用执行,比如(DPlayer的DPlayer对象,clipboard里的ClipboardJS对象),只有导出后才能使用,否则会报错对象不存在的错误

1
2
import DPlayer from "../assets/js/DPlayer.min.js";
import ClipboardJS from '../assets/js/clipboard.min.js'

举例说明:vue-cli下的剪切板组件nmsl.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<script scope>

import ClipboardJS from '../assets/js/clipboard.min.js'
export default {
name:"axios",
data() {
return {
loading: false,
rows:{}, // 嘴臭数据集
currentPage: 1, // 当前页数
limit:1, // limit偏差限制
count:0, // 返回数据量总数
}
},
mounted() {
this.getContent();
this.clip();
},
methods: {
clip:function () {
let btn = document.getElementById('btn');
let clipboard = new ClipboardJS(btn);
clipboard.on('success', function(e) {
btn.innerText='已复制';
setTimeout(function (){btn.innerText='复制'; },500);
});
},
getContent:function () {
let app = this;
axios({
url:"http://127.0.0.1:8001/nmsl/ndsl/10/",
method:"get",
headers:{
"Content-Type": "application/json"
},
params:{
offset: (this.currentPage-1)*this.limit,
limit: this.limit
}
})
.then(function(response){
if(response.status === 200 && (app.currentPage) <= response.data.count ){
app.count = response.data.count;
app.rows = response.data.result[0];
app.currentPage++;
}else{
app.rows = {"content":"暂无数据。。。"};
}
})
.catch(function (error) {
console.log(error);
});
}

}
}
</script>
  1. 在入口文件mian.js中引入css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import 'static/css/main.css'
import Vue from 'vue'
import './plugins/axios'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.config.productionTip = false;
Vue.use(ElementUI);

new Vue({
router,
render: h => h(App)
}).$mount('#app')

这样就可以直接使用了

3.项目开发前的准备☆

  • 划分项目的目录结构

  • vue-router路由设置

https://aqingya.cn/articl/245923b2.html

4.vue监听浏览器窗口大小变化

页面初始化mounted的时候,通过 document.body.clientWidth 和 document.body.clientHeight 来获取到浏览器的宽和高,然后通过 window.onresize 来监听浏览器窗口的变化,在这里来改变我们的变量宽和高即可。(created()的时候不行,因为此时document还没有生成)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<section class="p-10">
<h1> {{ screenWidth }} × {{ screenHeight }} </h1>
</section>
</template>
<script>
export default {
data() {
return {
screenWidth: '',
screenHeight: ''
};
},
mounted() {
this.screenWidth = document.body.clientWidth;
this.screenHeight = document.body.clientHeight;
window.onresize = () => {
return (() => {
this.screenWidth = document.body.clientWidth;
this.screenHeight = document.body.clientHeight;
})();
};
}
}
</script>

<style lang="scss">
</style>

5.vue-cli项目前后分离开发生产环境部署☆☆☆

前后分离概念

  • Django: Web框架,框架的作用在于处理request和 response,提供api,其他的不是框架所关心的内容。
  • Vue: 前端框架。
  • Nginx: Web代理服务器。处理静态文件的发送。动态请求则交予uWSGI处理。
  • uWSGI: 一个基于自有的uwsgi协议、WSGI协议和http协议的web网关。处理动态请求,将处理的结果回发给Nginx。

关于vue项目部署必需要考虑如下问题:

  1. 路由模式:hash(default),history
  2. api接口是否会有跨域问题

这里技术选型为history,必须详细看懂开发与生产环境部署

本地开发环境

  1. router目录下的index.js

当为本地开发环境时,需要注释掉base

1
2
3
4
5
const router = new VueRouter({
routes,
mode: 'history', // history表示去掉锚点,默认mode : 'hash'
// base: process.env.BASE_URL,
})
  1. vue.config.js文件(处理路由与跨域问题)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
module.exports = {
/**
* 开发环境路由设置
*/
publicPath: '/', // 这个是在测试路由为‘history’时,动态参数匹配params模式时才会使用

devServer: {
// port: 8000, // 配置开发环境运行端口号
// 配置代理,解决跨域请求后台数据的问题
proxy: {
'/migus':{
target: 'https://m.music.migu.cn/', // target host
ws: true, // proxy websockets
changeOrigin: true, // needed for virtual hosted sites
pathRewrite: {
'^/migus': '' // rewrite path
}
},
'/tophub':{
target: 'https://www.tophub.fun:8888/',
ws: true,
changeOrigin: true,
pathRewrite: {
'^/tophub': ''
}
}

}
}
}

当为本地开发环境时:publicPath必须为 /

1
2
3
module.exports = {
publicPath: '/', // 这个是在测试路由为‘history’时,动态参数匹配params模式时才会使用
}

开发环境的跨域问题利用devServer的Proxy可以轻松解决。比如此时的/migus代理,
其原api假如是:https://m.music.migu.cn/v1/api/comment ,设置代理后,axios访问api时,便是 migus/v1/api/comment

生产环境部署

  1. 开启router目录下的index.js的base属性
1
2
3
4
5
const router = new VueRouter({
routes,
mode: 'history', // history表示去掉锚点,默认mode : 'hash'
base: process.env.BASE_URL
})
  1. 开启vue.config.js里的publicPath
1
2
3
4
5
6
7
/**
* 生产环境打包设置
*/
publicPath: process.env.NODE_ENV === 'production' ? '/test/' : '/',
outputDir: 'dist/test',
assetsDir: 'static',
productionSourceMap: false, // 关闭map文件

为什么这里使用 /test/,而不是使用之前的 ./

这是因为我们设置的路由关系.我们的路由有多级目录,比如

  • /tools/json 二级目录
  • /nmsl/hidden/source 三级目录

打包好了的文件保存路径为:dist/test目录(包含js,css,html等),注意:此时的二级目录打包的test,在nginx中也会涉及到

  1. 解决生产环境下的跨域问题

生产环境的访问api处理与本地开发同理。比如此时的/migus代理,
其原api假如是:https://m.music.migu.cn/v1/api/comment ,设置代理后,axios访问api时,便是 migus/v1/api/comment

不同的是:生产环境的跨域处理是在nginx中设置反向代理的。


nginx的生产环境设置:nginx.conf

1
2
3
4
5
6
7
8
9
location /migus {
rewrite ^/migus/(.*)$ /$1 break;
proxy_pass https://m.music.migu.cn/;
}

location /tophub {
rewrite ^/tophub/(.*)$ /$1 break;
proxy_pass https://www.tophub.fun:8888/;
}

进入到 /usr/local/nginx/sbin目录下,测试配置文件是否正确

项目打包性能优化

参考文章

完整打包部署实例

  • vue.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
let webpack = require('webpack');

// 是否为生产环境
const isProduction = process.env.NODE_ENV !== 'development';
// gzip压缩
const CompressionWebpackPlugin = require('compression-webpack-plugin')

module.exports = {
/**
* 生产环境打包设置
*/
// publicPath: process.env.NODE_ENV === 'production' ? '/test/' : '/',
// outputDir: 'dist/test',
// assetsDir: 'static',
// productionSourceMap: false, // 关闭map文件

/**
* 开发环境路由设置
*/
publicPath: '/', // 这个是在测试路由为‘history’时,动态参数匹配params模式时才会使用

// 开发环境跨域处理
devServer: {
// port: 8000, // 配置开发环境运行端口号
// //配置代理,解决跨域请求后台数据的问题
proxy: {
'/migus':{
target: 'https://m.music.migu.cn/', // target host
ws: true, // proxy websockets
changeOrigin: true, // needed for virtual hosted sites
pathRewrite: {
'^/migus': '' // rewrite path
}
},
'/tophub':{
target: 'https://www.tophub.fun:8888/',
ws: true,
changeOrigin: true,
pathRewrite: {
'^/tophub': ''
}
}
}
},

// gzip压缩
configureWebpack: config => {
// 生产环境相关配置
if (isProduction) {
//gzip压缩
const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' + productionGzipExtensions.join('|') + ')$'
),
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
})
)
}
},
chainWebpack: config => {
config.plugin('provide').use(webpack.ProvidePlugin, [{
$: 'jquery',
jquery: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}])

// ============压缩图片 start============
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
// ============压缩图片 end============
},
configureWebpack:{
externals: {
'vue': 'Vue',
'element-ui': 'ELEMENT',
'axios': 'axios',
}
}
}
  • nginx.conf 配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
user root;
worker_processes 1;

events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
proxy_cache_path /var/cache/nginx/cache levels=1:2 keys_zone=imgcache:100m inactive=1d max_size=1g;


# 开启gzip
gzip on;

# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;

# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 2;

# 进行压缩的文件类型。javascript有多种形式,后面的图片压缩不需要的可以自行删除
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;

# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;

# 设置压缩所需要的缓冲区大小
gzip_buffers 4 16k;

# 虚拟主机1,用于找到vue页面
server {
listen 80;
server_name 127.0.0.1;

location / {
root /data/wwwroot/front/;
index index.html index.htm;
# 这一条参数确保vue页面刷新时候,不会出现404页面(注意这里的/test/)
try_files $uri $uri/ /test/index.html;
}

# 处理生产环境的跨域问题
location /migus {
rewrite ^/migus/(.*)$ /$1 break;
proxy_pass https://m.music.migu.cn/;
}

location /tophub {
rewrite ^/tophub/(.*)$ /$1 break;
proxy_pass https://www.tophub.fun:8888/;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

}

# 虚拟主机2,用于反向代理,找到django
server {
listen 8000;
# 向外映射的端口,通过此8000端口,其它电脑可访问Django的api接口:http:主机ip:8000/api接口
server_name 127.0.0.1;

location / {
uwsgi_pass 101.37.152.63:8080;
include /usr/local/nginx/conf/uwsgi_params;
}
}
}

ps:101.37.152.63:8080为Django的运行ip(不过我使用的是云服务器0.0.0.0:8080)


 评论

联系我 | Contact with me

Copyright © 2019-2020 谁知你知我,我知你知深。此恨经年深,比情度日久

博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议