VueJS项目创建
环境
安装cli工具
1
npm install -g @vue/cli rimraf yrm
项目搭建
新建项目
使用 vue 命令创建项目
1
2
3vue create project_name
cd project_name
npm install
vscode配置
eslint: 定义规范
prettier: 根据eslint的规则格式化代码
babel: javaScript的编译器
vscode的设置
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{
// vscode默认启用了根据文件类型自动设置tabsize的选项
"editor.detectIndentation": false,
// 重新设定tabsize
"editor.tabSize": 2,
// #每次保存的时候自动格式化
"editor.formatOnSave": true,
// #每次保存的时候将代码按eslint格式进行修复
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
// 添加 vue 支持
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "vue",
"autoFix": true
}
],
// #让prettier使用eslint的代码格式进行校验
"prettier.eslintIntegration": true,
// #去掉代码结尾的分号
"prettier.semi": false,
// #使用单引号替代双引号
"prettier.singleQuote": true,
// #让函数(名)和后面的括号之间加个空格
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
// #这个按用户自身习惯选择
"vetur.format.defaultFormatter.html": "js-beautify-html",
// #让vue中的js按编辑器自带的ts格式进行格式化
"vetur.format.defaultFormatter.js": "vscode-typescript",
"vetur.format.defaultFormatterOptions": {
"js-beautify-html": {
"wrap_attributes": "force-aligned"
// #vue组件中html代码格式化样式
}
},
"workbench.colorTheme": "Ayu Mirage",
"workbench.iconTheme": "vscode-icons",
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.quickSuggestions": {
"strings": true
},
"vetur.ignoreProjectWarning": true,
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"files.autoSave": "afterDelay"
}插件
vue代码片段
- Ctrl + Shift + P ,搜索 snippets, 找到vue.json
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104{
// Place your snippets for vue here. Each snippet is defined under a snippet name and has a prefix, body and
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
// same ids are connected.
// Example:
// "Print to console": {
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"Print to console": {
"prefix": "vue",
"body": [
"<!-- $1 -->",
"<template>",
"<div class='$2'>$5</div>",
"</template>",
"",
"<script>",
"",
"// 导入的其他文件 例如:import moduleName from 'modulePath';",
"",
"export default {",
"",
"//import所引入的组件注册",
"components: {",
"",
"},",
"",
"data() {",
" return {",
"",
" };",
"},",
"",
"//监听属性",
"computed: {",
"",
"},",
"",
"//监控data中的数据变化",
"watch: {",
"",
"},",
"",
"//方法集合",
"methods: {",
"",
"},",
"",
"//生命周期 - 组件实例刚被创建",
"beforeCreate() { ",
"",
"},",
"//创建完成 访问当前this实例",
"created() {",
"",
"},",
"//挂载之前",
"beforeMount() { ",
"",
"},",
"//挂载完成 访问DOM元素",
"mounted() {",
"",
"},",
"//更新之前",
"beforeUpdate() { ",
"",
"},",
"//更新之后",
"updated() { ",
"",
"},",
"//for keep-alive 缓存功能,组件被激活时调用",
"activated() {",
"",
"},",
"//for keep-alive 组件被移除时调用",
"deactivated() {",
"",
"},",
"//组件销毁之前调用",
"beforeDestroy() {",
"",
"},",
"//组件销毁之后调用",
"destroyed() {",
"",
"},",
"}",
"</script>",
"<style lang='scss' scoped>",
"//@import url($3); 引入公共css类",
"$4",
"</style>"
],
"description": "Log output to console"
}
}
vue-cli
Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:
- 通过
@vue/cli
实现的交互式的项目脚手架。 - 通过
@vue/cli
+@vue/cli-service-global
实现的零配置原型开发。 - 一个运行时依赖 (
@vue/cli-service
),该依赖:- 可升级;
- 基于 webpack 构建,并带有合理的默认配置;
- 可以通过项目内的配置文件进行配置;
- 可以通过插件进行扩展。
- 一个丰富的官方插件集合,集成了前端生态中最好的工具。
- 一套完全图形化的创建和管理 Vue.js 项目的用户界面。
- 通过
配置
- 如何配置Vue-CL创建项目的 webpack配置
- 认情况下通过Wue-CLI创建的项目己经自动给我们配置好了 webpack
- 但是有时候默认的配置可能不能满足我们的需求,例如我们想修改输出目录名称,想増加一些插件等,但是vue-CLI创建的项目里又没有 webpack配置文件,那么我们应该如何修改或增加 webpack配置呢?
- 我们可以通过新建vue.config.js的方式来修改配置
- 我们可以通过在vue.config.js中的
configureWebpack
属性来新增 原生的 webpack 配置 - vue.config.js配置参考 https://cli.vuejs.org/zh/config/
- webpack 配置 https://webpack.docschina.org/configuration/
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
29const path = require("path");
function resolve(dir) {
path.join(__dirname, dir);
}
module.exports = {
//打包文件输出路径,即打包到哪里
outputDir: "dist",
// 静态资源地址
assetsDir: "static",
// eslint-loader 是否在保存的时候检查
lintOnSave: false,
// 生产环境是否生成 sourceMap 文件
productionSourceMap: false,
filenameHashing: true, //文件hash
// chainWebpack 这个库提供了一个 webpack 原始配置的上层抽象,使其可以定义具名的 loader 规则
// 和具名插件,可以通过其提供的一些方法链式调用,在cli-service中就使用了这个插件
chainWebpack: () => {},
/*
configureWebpack是调整webpack配置最简单的一种方式,可以新增也可以覆盖cli中的配置。
可以是一个对象:被 webpack-merge 合并到webpack 的设置中去
也可以是一个函数:如果你需要基于环境有条件地配置行为,就可以进行一些逻辑处理,可以直接修改或
新增配置,(该函数会在环境变量被设置之后懒执行)。该方法的第一个参数会收到已经解析好的配置。
在函数内,你可以直接修改配置,或者返回一个将会被合并的对象。
*/
configureWebpack: {},
};
alias
使用chainWebpack
1
2
3
4
5chainWebpack: (config) => {
config.resolve.alias
// key,value自行定义,比如.set('@assets', resolve('src/assets'))
.set(key, value);
};configureWebpack方法
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// 对象形式
configureWebpack: {
resolve: {
alias: {
'@assets': resolve('src/assets')
}
}
};
// 函数形式
configureWebpack: config => {
if (isProduction) {
...
} else {
...
}
// 方式一:直接修改配置
config.resolve.alias['@asset'] = resolve('src/assets')
//方式二: 返回一个将要合并的对象
return {
resolve: {
alias: {
'@asset':resolve('src/assets')
}
}
}
}
全部配置
示例
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
33const path = require("path");
function resolve(dir) {
path.join(__dirname, dir);
}
module.exports = {
publicPath: "./", // 部署应用包时的基本 URL Default: '/'
outputDir: "dist",
assetsDir: "static", // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。
indexPath: "index.html", // 指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。 Default: 'index.html'
configureWebpack: (config) => {
if (process.env.NODE_ENV === "production") {
// 为生产环境修改配置...
config.mode = "production";
} else {
// 为生产环境修改配置...
config.mode = "development";
}
// 开发生产共同配置别名
Object.assign(config.resolve, {
alias: {
"@": path.resolve(__dirname, "./src"),
assets: path.resolve(__dirname, "./src/assets"),
common: path.resolve(__dirname, "./src/common"),
components: path.resolve(__dirname, "./src/components"),
network: path.resolve(__dirname, "./src/network"),
configs: path.resolve(__dirname, "./src/configs"),
views: path.resolve(__dirname, "./src/views"),
plugins: path.resolve(__dirname, "./src/plugins"),
},
});
},
};
全局样式
在 main.js 中引入
1
import "@/styles/index.scss"; // global css
在 src/styles/index.scc中编写
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@import "./element-ui.scss";
body {
margin: 0;
padding: 0;
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family:
Helvetica Neue,
Helvetica,
PingFang SC,
Hiragino Sans GB,
Microsoft YaHei,
Arial,
sans-serif;
}
label {
font-weight: 700;
}
html {
height: 100%;
box-sizing: border-box;
}
#app {
height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
a:focus,
a:active {
outline: none;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
div:focus {
outline: none;
}
.clearfix {
&:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
}
// main-container global css
.app-container {
padding: 20px;
}
引入element UI
按需引入
安装babel-plugin-component
1
npm install babel-plugin-component -D
在 babel.config.js 文件中添加下面配置
1
2
3
4
5
6
7
8
9
10
11
12module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
[
"component",
{
libraryName: "element-ui",
styleLibraryName: "theme-chalk",
},
],
],
};main.js 中引入element UI 组件
1
2
3
4
5import Vue from "vue";
import { Button, Select } from "element-ui";
Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
完整列表
ElementUI 完整的组件列表如下
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143import Vue from "vue";
import {
Pagination,
Dialog,
Autocomplete,
Dropdown,
DropdownMenu,
DropdownItem,
Menu,
Submenu,
MenuItem,
MenuItemGroup,
Input,
InputNumber,
Radio,
RadioGroup,
RadioButton,
Checkbox,
CheckboxButton,
CheckboxGroup,
Switch,
Select,
Option,
OptionGroup,
Button,
ButtonGroup,
Table,
TableColumn,
DatePicker,
TimeSelect,
TimePicker,
Popover,
Tooltip,
Breadcrumb,
BreadcrumbItem,
Form,
FormItem,
Tabs,
TabPane,
Tag,
Tree,
Alert,
Slider,
Icon,
Row,
Col,
Upload,
Progress,
Badge,
Card,
Rate,
Steps,
Step,
Carousel,
CarouselItem,
Collapse,
CollapseItem,
Cascader,
ColorPicker,
Transfer,
Container,
Header,
Aside,
Main,
Footer,
Loading,
MessageBox,
Message,
Notification,
} from "element-ui";
Vue.use(Pagination);
Vue.use(Dialog);
Vue.use(Autocomplete);
Vue.use(Dropdown);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Menu);
Vue.use(Submenu);
Vue.use(MenuItem);
Vue.use(MenuItemGroup);
Vue.use(Input);
Vue.use(InputNumber);
Vue.use(Radio);
Vue.use(RadioGroup);
Vue.use(RadioButton);
Vue.use(Checkbox);
Vue.use(CheckboxButton);
Vue.use(CheckboxGroup);
Vue.use(Switch);
Vue.use(Select);
Vue.use(Option);
Vue.use(OptionGroup);
Vue.use(Button);
Vue.use(ButtonGroup);
Vue.use(Table);
Vue.use(TableColumn);
Vue.use(DatePicker);
Vue.use(TimeSelect);
Vue.use(TimePicker);
Vue.use(Popover);
Vue.use(Tooltip);
Vue.use(Breadcrumb);
Vue.use(BreadcrumbItem);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Tabs);
Vue.use(TabPane);
Vue.use(Tag);
Vue.use(Tree);
Vue.use(Alert);
Vue.use(Slider);
Vue.use(Icon);
Vue.use(Row);
Vue.use(Col);
Vue.use(Upload);
Vue.use(Progress);
Vue.use(Badge);
Vue.use(Card);
Vue.use(Rate);
Vue.use(Steps);
Vue.use(Step);
Vue.use(Carousel);
Vue.use(CarouselItem);
Vue.use(Collapse);
Vue.use(CollapseItem);
Vue.use(Cascader);
Vue.use(ColorPicker);
Vue.use(Container);
Vue.use(Header);
Vue.use(Aside);
Vue.use(Main);
Vue.use(Footer);
Vue.use(Loading.directive);
Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$prompt = MessageBox.prompt;
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;
引入sass
安装对应的 loader 即可, sass-loader最新版本需要 webpack5,这里指定版本安装
1
2npm install sass-loader@^7.2.0 -D
npm install sass@^1.35.2 -D使用
1
<style lang="sass" scoped></style>
引入路由
安装依赖, 有二种方式
1
2
3
4# 方式一: vue命令安装
vue add router
# 方式二:npm 手动安装
npm install vue-router --save新建 router/index.js 文件
1
2
3
4
5import Vue from "vue";
import VueRouter from "vue-router";
// 使用VUE挂载vue-router
Vue.use(VueRouter);main.js导入
1
import router from './router'
使用路由
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
32export const constantRoutes = [
{
path: "/about",
component: () => import("@/views/About"),
hidden: true,
},
{
path: "/home",
component: () => import("@/views/Home"),
},
{
path: "/login",
component: () => import("@/views/login/index"),
hidden: true,
},
];
const createRouter = () =>
new VueRouter({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes,
});
const router = createRouter();
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter();
router.matcher = newRouter.matcher; // reset router
}
export default router;
引入Axios
文档
安装
1
npm install vue-axios --save
在main.js页面引用:
1
2
3import Vue from "vue";
import axios from "axios";
Vue.prototype.$axios = axios; //全局注册,使用方法为:this.$axios使用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<script>
export default{
data(){
return{
userId:666,
token:'',
}
},
created(){
this.$axios({
method:'post',
url:'api',
data:this.qs.stringify({ //这里是发送给后台的数据
userId:this.userId,
token:this.token,
})
}).then((response) =>{ //这里使用了ES6的语法
console.log(response) //请求成功返回的数据
}).catch((error) =>
console.log(error) //请求失败返回的数据
})
}
}
</script>多个请求
1
2
3
4
5
6
7
8
9
10
11
12
13function getUserAccount() {
return axios.get("/user/12345");
}
function getUserPermissions() {
return axios.get("/user/12345/permissions");
}
axios.all([getUserAccount(), getUserPermissions()]).then(
axios.spread(function (acct, perms) {
// Both requests are now complete
}),
);模版方法
1
2
3
4
5
6// axios.creat([config])
var instance = axios.create({
baseURL: "https://some-domain.com/api/",
timeout: 1000,
headers: { "X-Custom-Header": "foobar" },
});
axios拦截器
在请求前会出现一个动态的loading图,在响应后隐藏此loading图。
在请求或响应被
then
或catch
处理前拦截它们。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
return config;
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error);
},
);
// 添加响应拦截器
axios.interceptors.response.use(
function (response) {
// 对响应数据做点什么
return response;
},
function (error) {
// 对响应错误做点什么
return Promise.reject(error);
},
);
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 凉月の博客!
评论