Vue

前端目前形势

前端发展史

1.HTML(5)、CSS(3)、JavaScript(ES5、ES6):编写一个个的页面 -> 给后端(PHP、Python、Go、Java) -> 后端嵌入模板语法 -> 后端渲染完数据 -> 返回数据给前端 -> 在浏览器中查看

2.Ajax的出现 -> 后台发送异步请求,Render+Ajax混合

3.单用Ajax(加载数据,DOM渲染页面):前后端分离的雏形

4.Angular框架的出现(1个JS框架):出现了“前端工程化”的概念(前端也是1个工程、1个项目)

5.ReactVue框架:当下最火的2个前端框架(Vue:国人喜欢用,React:外国人喜欢用)

6.移动开发(Android+IOS) + Web(Web+微信小程序+支付宝小程序) + 桌面开发(Windows桌面):前端 -> 大前端

7.一套代码在各个平台运行(大前端):谷歌Flutter(Dart语言:和Java很像)可以运行在IOS、Android、PC端

8.在Vue框架的基础性上 uni-app一套编码 编到10个平台

9.在不久的将来 ,前端框架可能会一统天下

介绍

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架

与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用

Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合

渐进式框架

可以一点一点地使用它,只用一部分,也可以整个工程都使用它

网站

特点

  • 易用
    • 通过HTML、CSS、JavaScript构建应用
  • 灵活
    • 不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩
  • 高效
    • 20kB min+gzip 运行大小
    • 超快虚拟DOM
    • 最省心的优化

M-V-VM思想

介绍

MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,是一种事件驱动编程方式

  • Model :vue对象的data属性里面的数据,这里的数据要显示到页面中
  • View :vue中数据要显示的HTML页面,在vue中,也称之为“视图模板” (HTML+CSS)
  • ViewModel:vue中编写代码时的vm对象,它是vue.js的核心,负责连接 View 和 Model数据的中转,保证视图和数据的一致性,所以前面代码中,data里面的数据被显示中p标签中就是vm对象自动完成的(双向数据绑定:JS中变量变了,HTML中数据也跟着改变)

img

特性

  • 低耦合视图(View)可以独立于Model变化和修改,1个ViewModel可以绑定到不同的View上,当View变化的时候 Model可以不变,当Model变化的时候 View也可以不变
  • 可复用:可以把一些视图逻辑放在1个ViewModel中,让很多View重用这端视图的逻辑(以此减少代码冗余)
  • 独立开发开发人员可以专注于业务逻辑数据的开发(ViewModel),设计人员可以专注于页面设计
  • 可测试:界面元素是比较难以测试的,而现在的测试可以针对ViewModel来编写

MVVM的逻辑

img

组件化开发、单页面开发

类似于DTL中的include,每一个组件的内容都可以被替换和复用

img

单页面开发

  • 只需要一个页面,结合组件化开发来替换页面中的内容
  • 页面的切换只是组件的替换,页面还是只有一个index.html

版本

  • 1.X:使用得较少
  • 2.X:普遍使用
  • 3.X:刚出没多久,只有Beta版

引入方式

补充

  • 解释型的语言是需要解释器的
  • nodejs:一门后端语言

使用

模板语法

1
{{变量、js语法}}

指令之文本指令

1
2
3
4
v-html		# 让HTML字符串渲染成标题
v-text # 标签内容显示js变量对应的值
v-show # 放一个布尔值:为真 标签就显示;为假,标签就隐藏
v-if # 放一个布尔值:为真 标签就显示;为假,标签就隐藏(删除)

指令之事件指令

1
2
3
v-on:事件		# 触发事件(不推荐)
@事件 # 触发事件(推荐)
@[event] # 触发event事件(可以是其他任意事件)

Style与Class

数据的绑定

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
:属性名 = js变量/js语法

class: 字符串、三目运算符、数组、对象{red:true}
:class='js变量、字符串、js数组'

style: 字符串、三目运算符、数组[{backgreound:'red'}]、对象{red:true}

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.cls_obj_red{
background-color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- <p :class="cls_obj">阿巴阿巴</p>-->
<!-- <p :style="style_obj">滴滴答答</p>-->
</div>

<script>
var vm = new Vue({
el:'#app',
data:{
// cls_obj:{cls_obj_red:true}
// cls_obj:['cls_obj_red']
// cls_obj:'cls_obj_red'
// style_obj:'background-color:red'
// style_obj:[{backgroundColor:'red'},]
// style_obj:{backgroundColor:'red'}
}
})
</script>
</body>
</html>

条件渲染

指令 释义
v-if 相当于: if
v-else 相当于:else
v-else-if 相当于:else if
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.cls_obj_red{
background-color: red;
}
</style>
</head>
<body>
<div id="app">
<p v-if="show">嘀哩嘀哩</p>
<p v-if="type==1">1</p>
<p v-else-if="type==2">2</p>
<p v-else-if="type==3">3</p>
<p v-else="">Boom!</p>
</div>

<script>
var vm = new Vue({
el:'#app',
data:{
show:true,
type:1
}
})
</script>
</body>
</html>

列表渲染

v-if + v-for

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" href="bootstrap.min.css">

</head>
<body>
<div id="app">
<button @click="shopping_click" class="btn btn-primary">哔哩哔哩</button>
<table class="table table-hover table-striped">
<thead>
<tr>
<th>编号</th>
<th>商品名</th>
<th>单价</th>
</tr>
</thead>
<tbody>
<tr v-if="shopping.length==0">
<td>售罄</td>
<td>售罄</td>
<td>售罄</td>
</tr>
<tr v-else v-for="value,key in shopping">
<td>{{key+1}}</td>
<td>{{value.name}}</td>
<td>{{value.price}}</td>
</tr>
</tbody>
</table>
</div>

<script>
var vm = new Vue({
el:'#app',
data:{
shopping:[]
},
methods:{
shopping_click(){
this.shopping=[
{id:1,name:'小包子', price:188},
{id:2,name:'包子', price:288},
{id:3,name:'大包子', price:388}
]
}
}
})
</script>
</body>
</html>

v-for

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" href="bootstrap.min.css">

<style>
.cls_obj_red{
background-color: red;
}
</style>
</head>
<body>
<div id="app">
<p v-for="name in names">id:{{name.cid}} name: {{name.name}} age: {{name.age}}</p>
</div>

<script>
var vm = new Vue({
el:'#app',
data:{
names:[
{cid:1, name:'jerry', age:18},
{cid:2, name:'tom', age:19},
{cid:3, name:'哔哩哔哩', age:20}
]
}
})
</script>
</body>
</html>

数组更新与检测

1
2
3
4
<!--vue中使用的是虚拟DOM, 会和原生的DOM进行比较, 然后进行数据的更新,提高数据的刷新速度(虚拟DOM用了diff算法)-->

一定会触发DOM的比较,如果有数据变了,页面没变,使用该方法赋值 ↓
Vue.set(vm.class_obj, 'background', true)

过滤

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" href="bootstrap.min.css">

</head>
<body>
<div id="app">

<input type="text" @input="changeData" v-model="search" >
<p v-for="value in new_list">{{value}}</p>
</div>

<script>
var vm = new Vue({
el:'#app',
data:{
search:'',
list:['a', 'ab', 'b', 'bs'],
new_list:['a', 'ab', 'b', 'bs']
},
methods: {
changeData(){
this.new_list = this.list.filter(item=>{
return item.indexOf(this.search)>-1
})
}
}
})
</script>
</body>
</html>

事件修饰符

事件修饰符 释义
.stop 只处理自己的事件,父控件冒泡的事件不处理(阻止事件冒泡)
.self 只处理自己的事件,子控件冒泡的事件不处理
.prevent 阻止a链接的跳转
.once 事件只会触发一次(适用于抽奖页面)

使用修饰符时,顺序很重要,相应的代码会以同样的顺序产生

1
2
@click.prevent.self		:会阻止所有的点击
@click.self.prevent :只会阻止对元素自身的点击
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件修饰符</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- <ul @click="handleUl">-->
<ul @click.self="handleUl">
<!-- <li v-for="data in dataList" @click="handleLi">{{data}}</li>-->
<li v-for="data in dataList" @click.stop="handleLi">{{data}}</li>
<li><a href="http://www.baidu.com">不拦截</a></li>
<li><a href="http://www.baidu.com" @click="handleLink($event)">点击拦截</a></li>
<li><a href="https://www.baidu.com" @click.prevent="handleLink">点击拦截</a></li>
<li><button @click.once="test">只执行一次</button></li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
dataList: ['1','22','333','4444']
},
methods: {
handleUl(ev){
console.log('ul被点击了')
},
handleLi(){
console.log('li被点击了')
ev.stopPropagation() // 点击事件停止 冒泡(向父组件传递时间)
},
handleLink(ev){
ev.preventDefault()
},
test(){
alert('只触发1次')
}
}
})
</script>
</html>

数据的双向绑定(v-model的使用)

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" href="bootstrap.min.css">


</head>
<body>
<div id="app">

<input type="text" v-model="test">{{test}}
</div>

<script>
var vm = new Vue({
el:'#app',
data:{
test:'',
}
})
</script>
</body>
</html>

按键修饰符

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>按键修饰符</title>
<script src="./js/vue.js"></script>
</head>

<body>


<div id="app">

<input type="text" v-model="name" @keyup="handelKey1">
<input type="text" v-model="name" @keyup.enter="handelKey2">
<!-- <button @click="handelClick">点我</button>-->

</div>


</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: ''
},
methods: {
handelKey1(ev) {
console.log(ev)
if (ev.keyCode == 13) {
console.log('按下了回车')
}
},
handelKey2() {
console.log('回车键按下了')
},
handelClick(ev) {
console.log(ev)
}
}

})
</script>

</html>

表单控制

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表单控制</title>
<script src="./js/vue.js"></script>
</head>

<body>


<div id="app">

<h1>checkbox的选中与不选中</h1>
<p>用户名: <input type="text" v-model="name"></p>
<p>密码: <input type="password" v-model="password"></p>
<p><input type="checkbox" v-model="isRem">记住密码</p>
<button @click="submit">登录</button>
<hr>
<h1>性别单选:radio</h1>

<input type="radio" v-model="gender" value="1">
<input type="radio" v-model="gender" value="2">
<input type="radio" v-model="gender" value="3">其他
<br>
您选择的性别是:{{gender}}
<hr>
<h1>爱好多选:checkbox</h1>

<input type="checkbox" v-model="hobby" value="1">篮球
<br>
<input type="checkbox" v-model="hobby" value="2">足球
<br>
<input type="checkbox" v-model="hobby" value="3">美女
<br>
您的爱好是:{{hobby}}

</div>


</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: '',
password: '',
isRem: false,
gender: '',
hobby:[],
},
methods: {
submit() {
console.log(this.name)
console.log(this.password)
console.log(this.isRem)
}
}

})
</script>

</html>

购物车案例(全选、数量加减)

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" href="bootstrap.min.css">
</head>
<body>
<div id="app">

<table class="table-hover table table-striped">
<thead>
<tr>
<th>商品名</th>
<th>单价</th>
<th>数量</th>
<th>选择 <input type="checkbox" v-model="allCheck" @change="allChange"></th>
</tr>
</thead>
<tbody>
<tr v-for="shop in shop_list">
<td>{{shop.name}}</td>
<td>{{shop.price}}</td>
<td><button class="btn btn-primary" @click="click_down(shop)">-</button>{{shop.num}}<button class="btn btn-primary" @click="shop.num++">+</button></td>
<td><input type="checkbox" :value="shop" v-model="check_list" @change="oneChange"></td>
</tr>
</tbody>
</table>
总价为: {{get_price()}}
</div>


<script>
var vm = new Vue({
el: '#app',
data: {
shop_list:[
{name:'哔哩', price:123, num:2},
{name:'书', price:323, num:3},
{name:'滴滴', price:223, num:4},
],
check_list:[],
allCheck:false
},
methods:{
get_price(){
let total = 0
if (this.check_list.length > 0){
for (i in this.check_list){
total += this.check_list[i].num * this.check_list[i].price
}
}
return total
},
allChange(){
if (this.allCheck){
this.check_list = this.shop_list
}else {
this.check_list=[]
}
},
oneChange(){
if (this.check_list.length === this.shop_list.length){
this.allCheck = true
}else {
this.allCheck = false
}
},
click_down(shop){
if (shop.num >1){
shop.num --
}else {
shop.num = 1
}
}
}
})
</script>
</body>
</html>

v-model进阶

  • .lazy :并不是实时改变,而是在失去焦点或者按回车时才会更新
  • .number :将输入转换成Number类型
  • .trim :可以自动过滤输入首尾的空格
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-model进阶</title>
<script src="./js/vue.js"></script>
</head>

<body>


<div id="app">

<!-- <input type="text" v-model.lazy="name"> 输入内容是:{{name}}-->
<!-- <input type="text" v-model.number="name"> 输入内容是:{{name}}-->
<input type="text" v-model.trim="name"> 输入内容是:{{name}}

</div>


</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: ''

},

})
</script>

</html>

Vue生命周期钩子

img

钩子函数 描述
beforeCreate 创建Vue实例之前调用
created 创建Vue实例成功后调用(可以在此处发送异步请求后端数据)
beforeMount 渲染DOM之前调用
mounted 渲染DOM之后调用
beforeUpdate 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
updated 重新渲染完成之后调用
beforeDestroy 销毁之前调用
destroyed 销毁之后调用
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-model进阶</title>
<script src="./js/vue.js"></script>
</head>

<body>


<div id="app">

<!-- <child v-if="isShow"></child>-->
</div>


</body>
<script>
//定义一个组件
Vue.component('child', {
template: `
<div>
{{name}}
<br>
{{age}}
<button @click="name='Darker1'">更新数据1</button>
<button @click="name='Darker2'">更新数据2</button>
</div>`,
data() {
return {
name: 'Darker1',
age: 19
}
},

beforeCreate() {
console.group('当前状态:beforeCreate')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
created() {
console.group('当前状态:created')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
beforeMount() {
console.group('当前状态:beforeMount')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
mounted() {
console.group('当前状态:mounted')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
//用的最多,向后端加载数据,创建定时器等
console.log("页面已被vue实例渲染, data, methods已更新");
console.log('mounted')
this.t = setInterval(function () {
console.log('daada')
}, 3000)

clearInterval(this.t)

},
beforeUpdate() {
console.group('当前状态:beforeUpdate')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
updated() {
console.group('当前状态:updated')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
beforeDestroy() {
console.group('当前状态:beforeDestroy')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
destroyed() {
console.group('当前状态:destroyed')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
//组件销毁,清理定时器
clearInterval(this.t)
this.t = null
console.log('destoryed')
},


})


var vm = new Vue({
el: '#app',
data: {
isShow: true

},
methods:{
init(){
console.log('init')
},

},
mounted() {
console.log('mounted执行;了')
//ajax向后端获取数据
this.init()

},



})
</script>

</html>

与后端交互的几种方式

向后端发送ajax请求

三种方式

  • jQuery的ajax
  • fetch(原生)
  • axios(用的最多)

jQuery的ajax

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="./js/vue.js"></script>
</head>
<body>

<div id="app">
<div v-for="data in data_list">
<h3>{{data.name}}</h3>
<img :src="data.poster" alt="">
<h5>导演:{{data.director}}</h5>
</div>

</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
data_list: []
},
methods: {
get_data() {
//发送请求
// let _this=this
$.ajax({
url: 'http://127.0.0.1:5000/',
type: 'get',
success: (data) => {
let data_obj=JSON.parse(data)
// console.log(typeof data_obj)
this.data_list = data_obj.data.films
}
// success: function (data) {
// // console.log(data)
// _this.data_list = data
// }
})
}
},
mounted() {
this.get_data()
},
})
</script>
</html>

fetch(原生)

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>

<div id="app">
<div v-for="data in data_list">
<h3>{{data.name}}</h3>
<img :src="data.poster" alt="">
<h5>导演:{{data.director}}</h5>
</div>

</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
data_list: []
},
methods: {
get_data() {
//发送请求
fetch("http://127.0.0.1:5000/").then(res => res.json()).then(res => {
console.log(res.data.films)
this.data_list = res.data.films
})

}
},
mounted() {
this.get_data()
},
})
</script>
</html>

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
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>

<div id="app">

<div v-for="data in data_list">
{[ data.name ]}
<img :src="data.poster" alt="">
{[ data.director ]}
{[ data.synopsis ]}
</div>

</div>


<script>
var vm = new Vue({
el:'#app',
data:{
data_list:[]
},
delimiters:['{[', ']}'],
methods:{
get_data(){
axios({
url:'http://127.0.0.1:8090/index/',
methods:'get'
}).then(res=>{
this.data_list = res.data.data.films
})
}
},
mounted(){
this.get_data()
}
})
</script>
</body>
</html>

计算属性

优点

  • 在同一个页面中使用多次计算属性,不会多次执行
  • 不需要加括号,直接使用
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>

<div id="app">
<input type="text" v-model='name'>
<br>
您输入的是:{{get_name()}}
<br>
您输入的是2:{{get_name()}}

<hr>
<!-- 您输入的是:{{name.substring(0,1).toUpperCase()+name.substring(1)}}-->
<!-- 计算属性优点-->
<!-- 1 在同一个页面中使用多次计算属性,不会多次执行-->
<!-- 2 不需要加括号,直接使用-->


<br>
计算属性:您输入的是:{{upper_name}}
<br>
计算属性2:您输入的是:{{upper_name}}
计算属性2:您输入的是:{{upper_name}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name:''
},
computed:{

upper_name(){
console.log('计算属性我执行了')
return this.name.substring(0,1).toUpperCase()+this.name.substring(1)
},
},
methods:{
get_name(){
console.log('get_name我执行了')
return this.name.substring(0,1).toUpperCase()+this.name.substring(1)
},
}

})
</script>
</html>
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>

<div id="app">
<input type="text" v-model='search'>
<div v-for="data in new_list">
{{data}}
</div>


</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
search: '',
data_list: ['aaa', 'abc', 'abcde', 'abcdef', 'bbb', 'bac']
},
computed: {
new_list() {
return this.data_list.filter(item => {
return item.indexOf(this.search) > -1
})


}


},
methods: {}

})
</script>
</html>

虚拟dom和diff算法

其实呢不只是vue,react中在执行列表渲染时也会要求给每个组件添加key这个属性。
key简单点来说就是唯一标识,就像ID一样唯一性
要知道,vue和react都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面。而隐藏在背后的原理便是其高效的Diff算法。

只做同层级的对比
按照key值比较,出现新的key就插入
通组件对比

img

image-20201214225437290

具体实现

把树按照层级分解

image-20201214225736585

同key值比较

image-20201214225827633

通组件对比

image-20201214225913886

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="box">
<div v-if="isShow">111</div>
<p v-else>222</p>
<!--
{tag:div,value:111}
{tag:p,value:222}
直接不比较,直接删除div,新增p
-->

<div v-if="isShow">111</div>
<div v-else>222</div>
<!--
{tag:div,value:111}
{tag:div,value:222}
比较都是div,只替换文本内容
-->
</div>

详细:https://segmentfault.com/a/1190000020170310

组件

  • 介绍
  • 全局组件
  • 局部组件
  • 组建通信之父传子

介绍

1
2
3
4
5
6
7
1 组件的作用
扩展 HTML 元素,封装可重用的代码,目的是复用
例如:
有一个轮播图,可以在很多页面中使用,一个轮播有js,css,html
组件把js,css,html放到一起,有逻辑,有样式,有html

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>

<div id="app">

<myheader></myheader>

<div>我是div</div>

<myheader></myheader>

</div>
</body>
<script>


// 定义一个全局组件
// 组件可以有data,methods,computed....,但是data 必须是一个函数

Vue.component('myheader', {
template: `
<div>
<h1 style="background-color: greenyellow">我是全局组件:{{name}}</h1>
<button @click="handleClick">点我弹出美女</button>

</div>
`,
data(){
return {
name:'lqz'
}
},
methods:{
handleClick(){
alert('美女')
}
},
mounted(){},
computed:{

}


})

var vm = new Vue({
el: '#app',
data: {},

})
</script>
</html>

局部组件

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>

<div id="app">

<myheader></myheader>

<div>我是div</div>

<myheader></myheader>

<div></div>


</div>
</body>
<script>


// 定义一个全局组件
//组件可以有data,methods,computed....,但是data 必须是一个函数

Vue.component('myheader', {
template: `
<div>
<h1 style="background-color: greenyellow">我是全局组件:{{name}}</h1>
<button @click="handleClick">点我弹出美女</button>
<hr>
<child></child>

</div>
`,
data(){
return {
name:'lqz'
}
},
methods:{
handleClick(){
alert('美女')
}
},
mounted(){},
computed:{

},
components:{
child:{
template: `<div>
<span>{{age}}</span>
</div>`,
data(){
return {
age:19
}
},
methods:{

}
}
}


})

var vm = new Vue({
el: '#app',
data: {},

})
</script>
</html>

组建通信之父传子

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>

<div id="app">


<myheader :myname="name" :myshow="false"></myheader>

{{obj.length}}



</div>
</body>
<script>


// 定义一个全局组件
//组件可以有data,methods,computed....,但是data 必须是一个函数

Vue.component('myheader', {
template: `
<div>
<h1 style="background-color: greenyellow">我是全局组件:{{myname}}</h1>
<button @click="handleClick">点我弹出美女</button>
<br>
{{myshow}}
<hr>
<child v-if=""></child>

</div>
`,
data(){
return {
name:'lqz'
}
},
methods:{
handleClick(){
alert('美女')
}
},
mounted(){},
computed:{

},
components:{
child:{
template: `<div>
<span>{{age}}</span>
</div>`,
data(){
return {
age:19
}
},
methods:{

}
}
},
// props:['myname'] , //注册一下

// 属性验证
props:{
myname:String,
myshow:Boolean
},


})

var vm = new Vue({
el: '#app',
data: {
name:'egon'
},

})
</script>
</html>

组建通信之子传父(通过自定义事件)

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">

<navbar @myevent="handleEvent"></navbar>


</div>
</body>
<script>
// 定义全局组件
Vue.component('navbar', {
template: `
<div>
<h1>我是navbar</h1>
<hr>
<input type="text" v-model="name">
<br>

<button @click="handleClick">我是子组件的button</button>
</div>
`,
data() {
return {
name: 'lqz'
}
},
methods: {
handleClick() {
// 触发父组件中myevent这个自定义事件对应的函数执行
this.$emit('myevent',this.name)
}
}
})
var vm = new Vue({
el: '#box',
data: {},
methods: {
handleEvent(name) {
console.log('我执行了')
console.log('从子组件传递的name:'+name)
}
}

})
</script>
</html>
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">

<navbar @myevent="handleEvent" v-if="myshow"></navbar>


</div>
</body>
<script>
// 定义全局组件
Vue.component('navbar', {
template: `
<div>
<h1>我是navbar</h1>
<hr>

<button @click="handleClick">点我隐藏子组件</button>
</div>
`,
data() {
return {
// myshow: true
}
},
methods: {
handleClick() {
// 触发父组件中myevent这个自定义事件对应的函数执行
// this.myshow = !this.myshow
this.$emit('myevent', false)
}
}
})
var vm = new Vue({
el: '#box',
data: {
myshow: true
},
methods: {
handleEvent(show) {
this.myshow = show
}
}

})
</script>
</html>

ref属性

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
ref放在标签上,拿到的是原生节点
<br>
ref放在组件上,拿到的是组件对象(数据,方法,直接使用即可)
<hr>
<h1>ref用在标签上</h1>
<input type="text" ref="myinput">
<button @click="handleClick">点我触发事件</button>

<hr>
<h1>ref用在组件上</h1>
<navbar ref="mynavbar"></navbar>


</div>
</body>
<script>
// 定义全局组件
Vue.component('navbar', {
template: `
<div>
<h3>我是navbar</h3>
<hr>
</div>
`,
data() {
return {
myshow: true
}
},
methods: {
handleClick(a) {
console.log('父组件调用我,传入了:'+a)
}
}
})
var vm = new Vue({
el: '#box',
data: {
myshow: true
},
methods: {
handleClick() {
//this.$refs 取到一个对象,放着你在标签上写得ref对应的value值

//在父组件中直接取到了子组件的值(从子传到父)
// console.log(this.$refs.mynavbar.myshow)
//从父传子
// this.$refs.mynavbar.myshow='sss'
//调用子组件方法
this.$refs.mynavbar.handleClick('lqz')

}
}

})
</script>
</html>

事件总线

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">

<child1></child1>

<hr>
<child2></child2>




</div>
</body>
<script>
// 借助事件总线,实现跨组件通信
//定义一个事件总线

var bus=new Vue()

Vue.component('child1', {
template: `
<div>
<input type="text" v-model="msg">
<button @click="send_msg">发送</button>
<hr>
</div>
`,
data() {
return {
msg: ''
}
},
methods:{
send_msg(){
bus.$emit('suibian',this.msg)
}
}
})

Vue.component('child2', {
template: `
<div>
<h5>我收到的内容是:{{recv_msg}}</h5>
</div>
`,
data() {
return {
recv_msg:''
}
},
mounted(){
bus.$on('suibian',msg=> {
this.recv_msg=msg
})
}
})

var vm = new Vue({
el: '#box',
data: {},
methods: {}

})
</script>
</html>

动态组件

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">


<button @click="who='Home'">首页</button>
<button @click="who='User'">用户</button>
<button @click="who='Order'">订单</button>

<keep-alive>
<component :is="who"></component>
</keep-alive>

</div>
</body>
<script>

Vue.component('Home', {
template: `
<div>
首页
</div>
`,
data() {
return {}
},
})

Vue.component('User', {
template: `
<div>
用户组件
<input type="text" v-model="name">
</div>
`,
data() {
return {
name: ''
}
},
})
Vue.component('Order', {
template: `
<div>
订单页面
</div>
`,
data() {
return {}
},
})

var vm = new Vue({
el: '#box',
data: {
who: 'Home'
},

})
</script>
</html>

插槽

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">

<Home>阿斯顿发送到</Home>

<Order>
<button slot="b" @click="handleClick">我是个按钮</button>
</Order>


</div>
</body>
<script>

Vue.component('Home', {
template: `
<div>
首页
<div>
<slot></slot>
</div>

</div>
`,
data() {
return {}
},
})

Vue.component('Order', {
template: `
<div>
订单页面

<slot name="a"></slot>
<br>
我是一行数据
<br>
<slot name="b"></slot>


</div>
`,
data() {
return {}
},
})

var vm = new Vue({
el: '#box',
data: {
who: 'Home'
},
methods:{
handleClick(){
console.log('我被点了')
}
}

})
</script>
</html>

Vue-CLI 搭建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
1 ECMAScript,javascript,nodejs的关系
2 安装nodejs(安装解释器)
3 java:sun---》oracle(甲骨文)----》有些包,收费
-安卓使用java开发,涉及到版权
-jdk:java开发工具包,做java开发,需要安装它 1.5 1.8大更新 java 15
-jre:java运行环境,
-jvm:java虚拟机,最少要占200m内存空间


4 安装node,一路下一步
node:就是python命令
npm:就是python的pip命令,npm下载模块慢,我们使用cmpm下载
cnpm:阿里提供的
npm install -g cnpm --registry=https://registry.npm.taobao.org
5 安装vue脚手架
cnpm install -g @vue/cli

6 多出vue命令
vue create my-project: 创建出一个vue项目,等同于djagnoadmin createproject 名字
# OR
vue ui
7 开发
-使用pycharm开发vue项目
-装vue插件
8 运行起项目
-terminal中:npm run serve

1626408322582

1626408646319

1626409485838

vue项目目录介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
myfirstvue  # 项目名
-node_modules # 该项目所有的依赖,如果要把项目给别人,这个文件夹要删掉(很大)
-public # 文件夹
-favicon.ico #小图标
-index.html # 整个vue项目的index.html,单页面开发

-src # 核心
-store # 如果装了vuex,就会有这个文件夹
-router #如果装了vue router ,就会有这个文件夹
-assets # 存放资源文件(js,css,img)
-components # 小组件(在这写小组件)
-views #页面组件(在这写页面组件)
main.js # 整个项目的入口,核心配置
App.vue # 根组件

-package.json # 项目的依赖,不能删
-README.md # 介绍

vue组件介绍

1
2
3
4
每个组件有三部分组成
template:写html
script:写js
style:写css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>   
<div class="about">
<h1>写html</h1>
</div>
</template>

<script>

js代码

</script>

<style>

css代码

</style>

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
1 以后,新建一个页面组件,写三部分
2 在router下的index.js内配置一下
const routes = [
{ // / 路径,显示Home这个页面组件
path: '/',
name: 'Home',
component: Home
},
{
path: '/order',
name: 'Order',
component: Order
},
{
path: '/about',
name: 'About',
// component: () => import('../views/About.vue')
component: About,
}
]


3 在根vue中写
<div id="app">
<router-view/>
</div>

4 以后要跳转到某个页面
<router-link to="/路径">
<button>点我跳转到order</button>
</router-link>

在项目中新建组件和使用

1
2
3
4
5
6
7
8
9
10
11
12
13
1 在components文件夹创建一个 xx.vue
2 在其他组件中使用
-在scripts中
import HelloWorld from '../components/HelloWorld.vue'
export default {
name: 'Home',
components: {
HelloWorld
}
}

3 在html中直接使用
<HelloWorld/>

js导入导出语法(了解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1 有一些变量,函数,想在其他地方都用,可以写成一个包
新建一个文件夹,在文件夹中写index.js
在内部写函数,写变量,最后一定要导出
var name='lqz'
function add(a,b) {
return a+b
}
export default {
name,
add
}
2 在想用的位置,导入使用即可
import xx from '../lqz'
console.log(xx.add(1,2))

使用axios

1
2
3
4
1 安装 cnpm install axios
2 导入使用
import axios from 'axios'
axios.get('api/index/').then(res => {})

前端代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1 vue.config.js中module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://127.0.0.1:8000',
changeOrigin: true
}
}
},
}

2 使用axios发送请求
mounted() {
axios.get('api/index/').then(res => {
console.log(res.data)
this.data_list = res.data.data.films
})
}

bootstrap和jq的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1 安装
cnpm install jquery
cnpm install bootstrap@3

2 配置vue.config.js中
const webpack = require("webpack");
module.exports = {
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
"window.$": "jquery",
Popper: ["popper.js", "default"]
})
]
}
};

3 main.js中
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'

elementui的使用

1
2
3
4
5
6
1 安装
cnpm install element-ui -S
2 main.js中配置
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);