一.vue入门

1.HelloWorld

1
2
3
4
5
6
7
8
9
10
11
12
13
声明式编程
<div id="app">{{message}}</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: "Hello World!",
},
});
</script>


2.声明式编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<ul>
只需要声明这种结构
<li v-for="items in movies">{{items}}</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: "Hello World!",
movies: [1, 2, 3, 4, 5],
},
});
</script>

3.小案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id="app">
<h2>当前计数 {{counter}}</h2>

<button @click="add">+</button>
<button @click="sub">-</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
counter: 0,
},
methods: {
add: function () {
this.counter++;
},
sub: function () {
this.counter--;
},
},
});
</script>

4.options

1
2
3
4
5
6
7
8
9
10
11
el:
类型 : string或者HTMLElement
作用 : 决定vue实例会管理哪一个DOM

data:
类型 : Object|Function(组件当中data必须是一个函数)
作用 : vue实例对应的数据对象

methods:
类型 : {[key:string]:Function}
作用 : 定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中调用

5.vue生命周期

image-20210225152951630

1
2
3
4
5
6
7
事物从诞生到消亡的过程

生命周期函数
1.created
2.mounted


6.es6语法

1.let和const

1
2
3
4
5
6
7
8
let 块级作用域
const 常量
不可以被修改,定义的时候必须赋值
常量的含义是指向的对象不能被修改,但是可以改变对象内部的属性
const obj = {
name:'codelorin'
}

2.对象

1
2
3
const obj {
name,age,height
}

3.函数

1
2
3
4
5
6
7
8
9
const obj {
run(){

}
}
响应式参数
run(...num){

}

4.js遍历

1
2
3
4
5
let i in arr
i就是下标

let i of arr
i就是取出的一个个对象

5.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
1.filter必须返回一个boolean值,true自动加到数组,false则过滤掉
const nums = [1,2,3,4,5]
let newNums = nums.filter(
function(n){
return n<2;
})

2.map
let newNums = nums.map(function(n){
return n*2;
})
3.reduce
对数组中的内容进行汇总
第一个值回调函数
第二个preValue初始值
let total = nums.reduce(function(preValue,n){
return preValue+n
},0)


let total = nums
.filter(function (n) {
return n < 100;
})
.map(function (n) {
return n * 2;
})
.reduce(function (preValue, n) {
return preValue + n;
}, 0);

let total = nums
.filter((n) => n < 100)
.map((n) => n * 2)
.reduce((preValue, n) => preValue + n);

二.语法

1.插值操作

(1).双括号

(2).v-once

1
2
3
4
{{firstName+" "+lastName}}
{{message}}
{{firstName}}{{lastName}}

1
2
<h2 v-once>{{message}}</h2>
v-once不会响应式的变化

(3).v-html

1
2
<div> v-html="url"></div>
会渲染html代码

(4).v-text

1
2
v-text="message"
不够灵活

(5).v-pre

1
2
<h2 v-pre>{{message}}</h2>
不做任何处理直接输出

(6).v-cloak

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
在vue解析之前,div中有一个属性v-cloak
在vue 解析之后,div中没有一个属性v-cloak
所以我们可以通过可以属性

<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app" v-cloak>{{message}}</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
setTimeout(() => {
const app = new Vue({
el: "#app",
data: {
message: "你好啊",
},
methods: {},
});
}, 1000);
</script>

2.属性v-bind

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
<img v-bind:src="url" alt="" />
语法糖
<img :src="url" alt="" />

class的是否取决于boolean
对象语法
<h2 :class="{类名1:boolean,类名2:boolean}">{{message}}</h2>

<div id="app">
<h2 :class="{active: isActive,line:isLine}">{{message}}</h2>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: "你好啊",
isActive: true,
isLine: true,
},
});
可以写一个固定的属性在前面,classes太长可以在函数中返回
<h2 class="title" :class="classes">Hello World</h2>

数组语法
<h2 class="title" :class="[active,line]">Hello World</h2>



练习
<div id="app">
<ul>
<li
v-for="(item,index) in message"
@click="clickIndex=index"
:class="{active:clickIndex==index}"
>
{{item}}
</li>
</ul>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: ["海王", "海尔兄弟", "火影忍者", "进击的巨人"],
clickIndex: -1,
},
});
</script>

绑定sytle
<div id="app">
<h2 :style="{fontSize:finSize+'px'}">{{message}}</h2>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: "Hello",
finSize: 100,
},
});
</script>
<h2 " :style="[active,line]">Hello World</h2>

3.计算属性

(1).基本操作

1
2
3
4
5
computed: {
fullName: function () {
return this.firstName + " " + this.lastName;
},
},

(2).复杂操作

1
2
3
4
5
6
7
8
9
computed: {
totalPrice: function () {
let result = 0;
for (let i = 0; i < this.books.length; i++) {
result += this.books[i].price;
}
return result;
},
},

(3).setter / getter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 computed: {
fullName: {
//一般没有set方法,只读属性 set: function () {},

get: function () {
return this.firstName + " " + lastName;
},
},
},
get方法的简写
computed: {
fullName: function () {
return this.firstName + " " + lastName;
},
},

set方法
set: function (newValue) {
const names = newValue.split(' ')

},

(4).计算属性的缓存

1
计算属性会有缓存,运行次数会变少

4.v-on

(1).使用

1
2
3
4
5
6
7
8
9
@click="方法"
1.
vue会将event对象作为参数传递到方法当中
<button @click="test"></button>
test(event){}

2.有时候我们除了event对象还需要传入其他参数
<button @click="test(abc,$event)"></button>
test(abc,event){}

(2).修饰符

1
2
3
4
5
6
7
8
9
10
11
12
阻止冒泡->stop
<button @click.stop="test"></button>


阻止默认事件->prevent
<button @click.prevent="test"></button>

监听键盘点击->keyup keyup.enter回车
<button @keyup="test"></button>

只触发一次回调->once
<button @click.once="test"></button>

5.v-if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<h2 v-if="false">{{message}}</h2>

<h2 v-if="false">{{message}}</h2>
<h3 v-else>false</h3>

<h2 v-if="score>90">优秀</h2>
<h2 v-else-if="score>60">良好</h2>
<h3 v-else>及格</h3>

加入key可以让vue不复用dom
<label>用户账号</label>
<input type="text" id="username" placeholder="账号登录" key="username" />
</span>
<span v-else>
<label>邮箱登录</label>
<input type="text" id="email" placeholder="邮箱登录" key="email" />

6.v-show

1
2
3
4
5
6
7
8
            <span v-show="flag">
<label>用户账号</label>
<input type="text" id="username" placeholder="账号登录" key="username" />
</span>

v-if是操作dom树
v-show是通过内联样式设置display=none隐藏
如果是切换频繁的元素,建议v-show

7.v-for

1
2
3
4
5
6
7
8
9
10
11
12
遍历数组
<li v-for="item in arr">{{item}}</li>
<li v-for="(item,index) in arr">{{index+1}} {{item}}</li>

遍历对象
<li v-for="value in arr">{{value}}</li>
<li v-for="(value,key) in arr">{{key}} {{value}}</li>
<li v-for="(value,key,index) in arr">{{key}} {{value}} {{index}}</li>

绑定key使得dom效率更高
<li v-for="item in info" :key="item">{{item}}</li>

(1).数组的响应式

1
2
3
4
5
6
7
8
9
10
11
12
响应式
push
splice
unshift
shift
sort
reverse
非响应式
索引值修改元素

vue的方式 set
Vue.set(this.letter,0,'修改后的值')

8.过滤器

1
2
3
4
5
6
7
可以对一些东西进行一些操作
<td>{{item.price|showPrice}}</td>
filters: {
showPrice(price) {
return "$" + price.toFixed(2);
},
},

9.练习

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./style.css" />
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<table>
<thead>
<tr>
<th></th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{item.price|showPrice}}</td>
<td>
<button @click="sub(index)" :disabled="item.count <=1">-</button>
{{item.count}}
<button @click="add(index)">+</button>
</td>
<td><button @click="removeBook(index)">移出</button></td>
</tr>
</tbody>
</table>
<span>总价: {{totalPrice|showPrice}}</span>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
books: [
{ id: 1, name: "《算法导论》", date: "2006-9", price: 85.0, count: 1 },
{ id: 2, name: "《JAVA》", date: "2006-1", price: 59.0, count: 1 },
{ id: 3, name: "《编程珠玑》", date: "2006-10", price: 39.0, count: 1 },
{ id: 4, name: "《代码大全》", date: "2016-9", price: 128.0, count: 2 },
],
},
methods: {
add(index) {
this.books[index].count++;
},
sub(index) {
this.books[index].count--;
},
removeBook(index) {
this.books.splice(index, 1);
},
},
computed: {
totalPrice() {
let temp = 0;
for (let i of this.books) {
temp += i.price * i.count;
}
return temp;
},
},
filters: {
showPrice(price) {
return "$" + price.toFixed(2);
},
},
});
</script>
</body>
</html>

10.v-model

1
2
3
4
数据的双向绑定
<input type="text" v-model="message" />

<input type="text" :value="message" @input="message=$event.target.value" />

1.radio

1
2
3
4
5
6
7
8
9
10

<label for=""
><input type="radio" name="sex" value="男" v-model="message"
/></label>
<label for=""
><input type="radio" name="sex" value="女" v-model="message"
/></label>
<p>{{message}}</p>
<input type="submit" value="123" />
message: "男",

2.checkbox

1
2
3
4
5
         <input type="checkbox" name="" value="1" v-model="message" />
<input type="checkbox" name="" value="2" v-model="message" />
<input type="checkbox" name="" value="3" v-model="message" />
<input type="checkbox" name="" value="4" v-model="message" />
message: [],

3.select

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
单选            
<select name="123" v-model="fruit">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>

多选 <select name="123" v-model="fruit" multiple>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>

4.值绑定

1
2
3
4
5
6
<label :for="item" v-for="item in originHobbies"
><input type="checkbox" :value="item" :id="item" v-model="hobby" />{{item}}</label
>

originHobbies: ["篮球", "足球", "乒乓球"],
hobby: [],

5.修饰符

1
2
3
4
5
6
7
8
lazy 失去焦点或者回车才记载数据
<label for="">输入: <input type="text" v-model.lazy="hobby" /></label>

number 输入数字
<label for="">输入: <input type="text" v-model.number="hobby" /></label>

trim去除两边空格
<label for="">输入: <input type="text" v-model.trim="hobby" /></label>

三.组件化

1.创建组件构造器

1
2
3
4
5
6
7
8
9
10
const cpnC = Vue.extend({
template: `
<div>
<h2>titile</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
`,
});

2.注册组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
全局注册,可以在多个vue实例下使用
Vue.component("cpn", cpnC);
第一个参数为为组件标签名,第二个为组件构造器

局部组件
const app = new Vue({
el: "#app",
data: {},
methods: {},
components: {
cpn: cpnC,
},
});
注册组件的语法糖
Vue.component("cpn", {
template: `
<div>
<h2>titile</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
`,
});

3.使用组件

1
必须挂载到vue实例下

3-1.最佳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>123</div>
</template>

<script src="vue.js"></script>

<script>
const cpn = {
template: "#cpn",
};

const app = new Vue({
el: "#app",
data: { },
methods: {},
components: {
cpn,
},
});
</script>

4.父子组件

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
         const cpnC1 = Vue.extend({
template: `
<div>
<h2>titile</h2>
<p>我是儿子</p>
<p>我是内容2</p>
</div>
`,
});
const cpnC2 = Vue.extend({
template: `
<div>
<h2>titile</h2>
<p>我是父亲</p>
<p>我是内容2</p>
<cpn1></cpn1>
</div>
`,
components: {
cpn1: cpnC1,
},
});


root组件
const app = new Vue({
el: "#app",
data: {},
methods: {},
components: {
cpn2: cpnC2,
},
});

5.组件模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1.        <script type="text/x-template" id="cpn">
<div>
<h2>titile</h2>
<p>我是哈哈哈</p>
<p>我是内容2</p>
</div>
</script>

2.
<template id="cpn">
<div>
<h2>titile</h2>
<p>我是哈哈哈</p>
<p>我是内容2</p>
</div>
</template>

6.组件的data为什么必须是函数

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
 const cpnC1 = Vue.extend({
template: cpn,
data() {
return {
title: "我是title",
};
},
});

Vue.component("cpn", {
template: "#cpn",
data() {
return {
counter: 0,
};
},

如果返回的是一个对象,那组件用的都是一个对象的内容,会造成连锁反应

如果需要返回同一个对象,可以使用下面的写法
const obj = {
counter: 0,
};


data() {
return obj;
},

7.父子组件之间的通信

1.父向子通信

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
props

<cpn1 :cmovies="movies"></cpn1>
<template id="cpn">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
</div>
</template>
1.使用数组
props: ["cmovies"],

2.使用对象
props: {
cmovies: Array,
},

字符串
props: {
cmovies: {
type: String,
default: "aaaa",
required: true,
},
},
对象或者数组 默认值必须以工厂函数返回一个默认值
props: {
cmovies: {
type: Array,
default() {
return [];
}
required: true,
},
},

2.子向父通信

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
自定义事件

<div id="app">
//接受子组件过来的事件
<cpn @item-click="cpnClick"></cpn>
</div>
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>

<script src="vue.js"></script>

<script>
const cpn = {
template: "#cpn",
data() {
return {
categories: [
{
id: "1",
name: "热门推荐",
},
{
id: "2",
name: "手机数码",
},
{
id: "3",
name: "家用家电",
},
{
id: "4",
name: "电脑办公",
},
],
};
},
methods: {
btnClick(item) {
//发射到父组件
this.$emit("item-click", item);
},
},
};

const app = new Vue({
el: "#app",
data: { movies: [1, 2, 3, 4, 5] },
methods: {
cpnClick(item) {
console.log(item.name);
},
},
components: {
cpn,
},
});
</script>

3.父访问子

(1).$children
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
const app = new Vue({
el: "#app",
data: {
message: "",
},
methods: {
btnClick() {
console.log(this.$children);

for (let i of this.$children) {
console.log(i.name);
i.showMessage();
}
},
},
components: {
cpn: {
template: "#cpn",
data() {
return {
name: "woshi cpn",
};
},
methods: {
showMessage() {
console.log("123");
},
},
},
},
});
(2).$refs
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
<cpn ref="aaa"></cpn>
默认是一个空对象,必须在组件标签加入ref="aaa"
const app = new Vue({
el: "#app",
data: {
message: "",
},
methods: {
btnClick() {
console.log(this.$refs);
},
},
components: {
cpn: {
template: "#cpn",
data() {
return {
name: "woshi cpn",
};
},
methods: {
showMessage() {
console.log("123");
},
},
},
},

4.子访问父

(1).parent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const app = new Vue({
el: "#app",
data: {
message: "123",
},
methods: {},
components: {
cpn: {
template: "#cpn",

methods: {
btnClick() {
console.log(this.$parent);
},
},
},
},
});

8.插槽slot

1.基本使用

1
2
3
4
5
6
7
8
9
10
为了让我们的组件有更好的扩展性

<template id="cpn">
<div>
<span>我是组件</span>
<slot></slot>
</div>
</template>
slot可以设置一个默认值
<cpn><button>插槽</button></cpn>

2.具名插槽的使用

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
使用
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>

<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>

<template v-slot:footer>
<p>Here's some contact info</p>
</template>
模板
<template id="cpn">
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>

显示
<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>

3.编译作用域

1
2
在哪里使用,作用域就在哪里
父找父 子找子

4.作用域插槽的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
父组件替换插槽的标签,但是内容由子组件来提供
<current-user>
子组件
<span>
<slot :user="user">
{{ user.lastName }}
</slot>
</span>
</current-user>

使用
<current-user>
<template v-slot="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>

四.模块化开发

1.匿名函数解决

1
2
3
4
5
6
7
8
9
10
11
12
13

(function(){
})()
会造成无法复用一些代码段

导出对象
let obj = {};
obj.flag = flag;
obj.sun = sun;
return obj
然后就可以使用对象里面的东西了
我们只需要保证模块名称不一样

2.commonJs

1
2
3
4
5
6
7
导出
module.exports = {

}
导入
let {xx,xx} = require("文件名")

3.ES

1
2
3
4
5
6
需要设置html代码引入js文件的类型设置为module
export {
flag,sum
}

import { } from "文件名";

五.webpack

1
2
3
模块化打包工具

webpack .\src\main.js dist/bundle.js

1.config

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
npm install webpack@3.6.0 -g 全局安装

npm init 初始化

const path = require("path");

module.exports = {
entry: "./src/main.js",
output: {
path: path.join(__dirname, "dist"),
filename: "bundle.js",
},
};
配置 npm run build
{
"name": "meetwevpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.6.0"
}
}


npm install webpack@3.6.0 --save--dev 局部安装

2.loader

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
const path = require("path");

module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
// 涉及到url自动添加路径
publicPath: "dist/",
},
module: {
rules: [
{
// 转义. 匹配所有css文件
test: /\.css$/,
// css-loader只负责将css文件进行加载
// style-loader负责将样式添加到DOM中
// 使用多个loader的时候,从右向左读取
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: [
{
loader: "style-loader", // 从 JS 中创建样式节点
},
{
loader: "css-loader", // 转化 CSS 为 CommonJS
},
{
loader: "less-loader", // 编译 Less 为 CSS
},
],
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: "url-loader",
options: {
// 当加载的图片小于limit时,会将图片编译成base64字符串形式
// 大于的话会报错,Cannot find module 'file-loader'
// npm install file-loader --save-dev
// 没有显示?报错文件找不到 路径 b939991dba660315bb66570ce2e58b6b.jpg
// base64不需要单独的文件进行存储
// 文件需要打包 添加publicPath
limit: 8000,
// 命名规范
name: "img/[name].[hash:8].[ext]",
},
},
],
},
{
test: /\.m?js$/,
// 排除
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: ["es2015"],
},
},
},
],
},
};


resolve: {
// 扩展名省略
extensions: [".js", ".css", ".vue"],
alias: {
vue$: "vue/dist/vue.esm.js",
},
},
plugins: [
new webpack.BannerPlugin("最终版权归aaa所有"),
new HtmlWebpackPlugin({
template: "index.html",
}),
// 开发阶段不推荐打开 js代码压缩
// new UglifyjsWebpackPlugin(),
],
devServer: {
//为哪一个文件进行服务
contentBase: "./dist",
// 是否实时更新
inline: true,
},

六.Vue-cli

1
2
3
4
5
6
npm install -g @vue/li
npm install @vue/cli-init -g

vue init webpack demo 项目初始化

vue create xxx

七.vue-router

1.路由操作

1
2
3
4
5
6
7
8
9
10
location.hash = ''
location.href = ''
history.pushState.({},'','home')
history.foward()
history.back()
任意回退
history.go()
回退不可以点击
histrory.repalceState({},'','about')

2.vue-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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<router-link to="/home">Home</router-link> |
<router-link to="/about">About</router-link>

显示的标签
<router-view/>

改为history模式
const router = new VueRouter({
routes,
mode: "history"
});

botton
<router-link to="/home" tag="button">首页</router-link>
<router-link to="/about" tag="button">关于</router-link>

不能返回
<router-link to="/home" tag="button" replace>首页</router-link>
<router-link to="/about" tag="button" replace>关于</router-link>

活跃状态的class
<router-link to="/home" tag="button" replace active-class="active">首页</router-link>
<router-link to="/about" tag="button" replace active-class="active">关于</router-link>
或者统一在路由中修改
routes,
mode: "history",
linkActiveClass: "active"
自己写标签修改路由
<div id="app">
<button @click="home()">首页</button>
<button @click="about()">关于</button>
<router-view/>
</div>
</template>

<script>
export default {
name: 'App',
methods:{
home(){
this.$router.replace('/home');
},about(){
this.$router.replace('/about');
}
}
}
</script>

3.动态路由

1
2
3
4
5
6
7
8
9
10
11
12
  {
path: "/user/:userid",
component: User
}

<router-link :to="'/user/'+userid" >首页</router-link>

computed:{
userId(){
return this.$route.params.userId
}
}

4.路由的软加载

1
2
3
const Home = () => import("../components/Home.vue");
const About = () => import("../components/About.vue");
const User = () => import("../components/User.vue");

5.嵌套路由

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
<template>
<div>
<h2>我是首页</h2>
<router-link to="/home/news" >新闻</router-link>
<router-link to="/home/messages" >信息</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'Home',
}
</script>
<style scoped>

</style>


path: "/home",
component: Home,
children: [
{
path: "news",
component: News
},
{
path: "messages",
component: Messages
}
]

6.传递数据

1
2
3
 <router-link :to="{path:'/profile',query:{name:id,imgUrl:imgUrl}}" >档案</router-link>
$route.query.name

7.全局导航守卫

1
2
3
4
5
6
7
8
9
10
前置钩子hook
router.beforeEach((to, from, next) => {
document.title = to.meta.title; //to.matched[0].meta.title;
next();
});

后置钩子
router.afterEach((to,from)=>{

})
1.keep-alive
1
2
3
4
5
6
7
8
9
保留状态

<keep-alive >
<router-view />
</keep-alive>
排除
exclude="Profile,User"
包含
include

八.promise

1.base

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
new Promise((resolve, reject) => {
setTimeout(() => {
console.log("处理ing");
resolve();
}, 1000);
})
.then(() => {
console.log("处理ing2");
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000);
});
})
.then(() => {
console.log("end");
});


new Promise((resolve, reject) => {
setTimeout(() => {
console.log("处理ing");
resolve();
}, 1000);
})
.then(() => {
console.log("处理ing2");
})
.catch(() => {
console.log("处理失败");
});
或者
new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("Hello Vuejs");
reject("error message");
}, 1000);
}).then(
(data) => {
console.log(data);
},
(err) => {
console.log(err);
}
);

2.all方法

1
Promise.all([new Promise((resolve, reject) => {}), new Promise((resolve, reject) => {})]);

九.vuex

1.初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
state: {},
mutations: {},
actions: {},
getters: {},
modules: {}
});

export default store;

2.具体使用

不是响应式想要使用可以使用Vue.set或者Vue.delete方法

(1).state(变量)

(2).mutations(方法)

1
2
3
4
5
6
7
使用  方法(state){
state.xxx
}
修改 this.$store.commit('方法名称')



(3).getters(计算属性)

(4).modules

1
2
3
4
5
modules:{
a:{

}
}

(5).action

1
2
3
4
5
6
异步操作

方法名称(context){
context.commit('方法名称')
}
使用 this.$store.dispatch('方法名称')

十.axios

1.基本使用

1
2
3
4
5
6
7
8
9
10
11
axios({
url: "http://123.207.32.32:8000/home/multidata",
method: "get",
parms:{

},

}).then(res => {
console.log(res);
});

2.并发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
axios
.all([
axios({
url: "http://123.207.32.32:8000/home/multidata"
}),
axios({
url: "http://123.207.32.32:8000/home/data",
params: {
type: "sell"
}
})
])
.then(result => {
console.log(result);
});

可以使用spread分割
.then(
axios.spread((res1, res2) => {
console.log(res1);
console.log(res2);
})
);

3.配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
全局
axios.defaults.baseURL
axios.defaults.timeout

创建实例
const instance1 = axios.create({
baseURL: "http://123.207.32.32:8000",
timeout: 5000
});

instance1({
url: "/home/multidata"
}).then(res => {
console.log(res);
});


4.network文件夹

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
最好建立一个network文件专门进行网络请求
export function request(config) {
return new Promise((resolve, reject) => {
const instacne = axios.create({
baseURL: "http://152.136.185.210:8000/api/z8",
timeout: 5000,
});

// 发送真正的网络请求
instacne(config)
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}


最终版
export function request(config) {
const instacne = axios.create({
baseURL: "http://152.136.185.210:8000/api/z8",
timeout: 5000,
});

// 发送真正的网络请求
return instacne(config); // 返回值本来就是Promise
}

import { request } from "./network/request";

request({
url: "/home/multidata",
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});

5.拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export function request(config) {
const instacne = axios.create({
baseURL: "http://123.207.32.32:8000",
timeout: 5000
});
//拦截器
instacne.interceptors.request.use(
config => {
console.log(config);
return config;
},
err => {
console.log(err);
}
);
return instacne(config);
}