HtuPengyuyan

HtuPengyuyan

  • 主页
  • 归档
所有文章 友链 关于我

HtuPengyuyan

HtuPengyuyan

  • 主页
  • 归档

Vue基础

2022-07-06

Vue简介

1.Javascript框架
2.简化DOM操作
3.响应式数据驱动

初识Vue

1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象
2.root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法
3.root容器里的代码被称为{vue模板}
4.Vue实例和容器时一一对应的
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用
6.中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性
7.一旦data中的数据发生改变,那么页面中用到的该数据的地方也会自动更新

注意区分:js表达式 和 js代码(语句)
1.表达式:一个表达式会产生一个值,可以放在一个需要值的地方:
1.a
2.a+b
3.demo(1)函数
4.x===y?’a’:’b’
2.js代码(语句)
1.if(){}
2.for(){}

第一次写页面就出现了warn警告,发现是data写成date了

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
{{ message }}
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
message: "你好HtuPengyuyan"
}
})
</script>

el挂载点

1.Vue会管理el选项命中的元素及其内部的后代元素
2.可以使用其他的选择器,但是建议使用id选择器
3.可以使用其他双标签,布恩那个使用HTML和body

data数据对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id="app">
{{message}}
<h2>{{school.name}}{{school.mobile}}</h2>
<ul>
<li>{{campus[0]}}</li>
<li>{{campus[1]}}</li>
</ul>
</div>
var app=new Vue({
el:"#app",
data:{
message:"你好小黑",
school:{
name:"黑马程序员",
mobile:"400-618-9090"
},
campus:["北京","上海","广州","深圳"]

}
})

data数据对象和el挂载点的两种写法

1.el有两种写法
1.new Vue时候配置el属性
2.先创建Vue实例,随后再通过vm.$mount(‘#root’)指定el的值
2.data有两种写法
1.对象式
2.函数式
3.一个重要原则
有Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const v=new Vue
//({
//el:'#root',
// data:{
// name:'xxx'
// }
// })
setTimeout(()=>{
v.$mount('#root')
},1000)
data:function(){
return{
name:'xxx'
}
}

MVVM模型

1.M:模型(Model):data中的数据
2.V:视图(View):模板代码
3.VM:视图模型(ViewModel):Vue实例

观察发现:

1.data中所有的属性,最后都出现在了vm身上。
2.vm身上所有的属性及Vue原型上所有的属性,在Vue模板中都可以直接使用

数据代理

回顾defineProperty()

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>
let number =18
let person={
name:'xxx',
sex:'男',
// age:'18',
}
//调用defineProperty给age值
Object.defineProperty(person,'age',{
// value:18
//enumberable:true//控制属性是否可以枚举,默认值时false
//writable:true//控制属性是否可以被修改,默认值时false
//configurable:true//控制属性是否可以被删除,默认值是false
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值时age的值
get(){
return number
},
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值时age的值
set(){
number=value
}

})
</script>

数据代理

定义:通过一个对象对另一个对象中属性的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
let obj={x:100}
let obj2={y:200}
Object.defineProperty(obj2,'x',{
get(){
return obj.x
//调用obj.x的值
},
set(value){
obj.x=value
}
})
</script>

Vue中的数据代理

通过vm对象来代理data对象中属性的操作

Vue中数据代理的好处:

更加方便的操作data中的数据

基本原理

1.通过Object.defineProperty()把data对象中所有属性参加到vm上
2. 为每一个参加到vm上的属性,都指定一个getter/setter
3. 在getter/setter内部去操作(读/写)data中对应的属性

事件修饰符

Vue中的事件修饰符:
1.prevent:阻止默认事件(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式;
5.self:只有eventtarget是当前操作的元素时才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;

1
<button @click.stop='showInfo'>点我提示信息</button>

键盘事件

1.Vue中常用的按键别名
回车 => enter
删除 => delete(捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab
上 => up
下 => down
左 => left
右 => right

2.系统修饰键(用法特殊):ctrl、alt、shift、meta
1.配合keyup使用:按下修饰键同时,再按下其他键,随后释放其他键,事件才被触发
2.配合keydown使用:正常触发事件

3.Vue.config.keyCodes.自定义键名=键码,可以定制按键别名
1
<input type="text" placeholder="按下回车提示输入" @keydown.tab="showInfo">

计算属性

1.定义:要用的属性不存在,要通过已有的属性计算得来
2.原理:底层借助了Objcet.defineproperty的方法提供getter和setter
3.get函数什么时候执行?
(1).初次读取时会执行一次
(2).当依赖的数据发生变化时会再次调用
4.优势:与methods实现相比,内部有缓存机制(可以重复用),效率更高,调试方便。
5.备注:
1.计算属性最终会出现在vm上,直接读取使用即可
2.如果计算属性要被修改,那必须写set函数相应修改,且set中要引起计算时依赖的数据发生变动

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
<div id="root">
姓: <input type="text" v-model="firstName"><br><br>
<!-- 这里用v-model实现双向绑定 -->
名: <input type="text" v-model="lastName"><br><br>
全名<span>{{fullName}}</span><br><br>
全名<span>{{fullName}}</span><br><br>
全名<span>{{fullName}}</span><br><br>
全名<span>{{fullName}}</span><br><br>
</div>

<script src="vue.js"></script>
<script>
const vm = new Vue({
el: "#root",
data: {
firstName: '张',
lastName: '三'
},
methods: {

},
computed: {
fullName: {
get() {
//get有什么用?当有人读取fullName时,get就会被调用,且返回值作为fullName的值
//get什么时候可以调用?1.初次读取fullName时
//所以来的数据发生变化时
console.log('get被调用了', this)
//console.log(this)//此处的this是vm
return this.firstName + '-' + this.lastName
},
set(value) {
//set调用时,fullName被修改时
console.log('set', value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
})
</script>

监视属性

Vue监视数据的原理:
1.Vue会监视data中所有层次的数据。
2.如何监视对象中的数据?
通过setter实现监视,且要在new Vue时就传入要检测的数据
(1).对象中后加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target.propertyName/index,value)或
vm.$set(target.propertyName/index,value)
3.如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新
(2).重新解析模板,进而更新页面
4.Vue修改数组中的某个元素一定要使用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
2.Vue.set()或vm.$set()
特别注意:Vue.set()或vm.$set()不能给vm或vm的跟数据对象添加属性

1
 

天气案例

监视属性watch:
1.当被监视的属性变化时,回调函数自动调用,进行相关操作
2.监视的属性必须存在,才能进行监视!!
3.监视的两种写法:
1.new Vue传入watch配置
2.通过vm.$watch监视

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
    <div id="root">
<h2>今天天气很{{info}},{{x}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
<script src="vue.js"></script>
<script>
const vm= new Vue({
el:'#root',
data:{
isHot:true,
x:1
},
computed:{
info(){
return this.isHot?'炎热':'寒冷'
}
},
methods: {
changeWeather(){
this.isHot=!this.isHot
this.x++
}
},
watch:{
isHot:{
immediate :true,//初始化时让handler调用一下
//handler函数什么时候调用?当isHot发生改变时
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}
}
})

深度监视

1.Vue中的watch默认不监测对象内部值的改变(一层)
2.配置deep:true可以监测对象内部值的改变(多层)
备注:
1.Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
2.使用watch时根据数据的具体结构与,决定是否采用深度监视

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
const vm= new Vue({
el:'#root',
data:{
isHot:true,
x:1,
d:{
c:{
e=100
},
f:{

}

}
},

watch:{
d:{
deep:true
handler(){

}
}
}
})

计算属性(computed)和监视属性(watch)的区别

1.computed能完成的功能,watch都可以完成
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
####两个重要的小原则
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象
2.所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数,promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件实例对象

1
2
3
4
5
6
7
8
9
10
11
<script>
watch:{
firstName(val){
//这里的定时器函数要用箭头函数函数的指向才是this
setTimeout(()=>{
consoule.log(this)
this.fullName=val+'-'+this.lastName
},1000)
}
}
</script>

vue的各种指令

1.v-text指令

使用v-text属性会使内容被替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<h2 v-text="message+'!'">深圳哦</h2>
<h2 v-text="info+'!'">深圳12300</h2>

<h2>{{message+"!"}}深圳</h2>
</div>
<script src="vue.js"></script>
<script>
var app= new Vue({
el:"#app",
data:{
message:"黑马程序员!!!",
info:"前端与移动端"
}
})
</script>

v-html指令

v-html的指令作用是:设置元素的innerhtml
内容中有html结构会被解析为标签
v-text指令无论内容是什么,只会解析为文本

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<p v-html="content"></p>
<p v-text="content"></p>
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
content: "<a href='http://www.itheima.com'>黑马程序员</a>"
}
})
</script>

v-on指令

v-on指令在methods里写下将要做的函数

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">
<input type="button" value="v-on指令" v-on:click="doIt">
//可缩写为@
<input type="button" value="v-on简写" @click="doIt">
<input type="button" value="双击事件" @dblclick="doIt">
<h2 @click="changeFood">{{ food }}</h2>
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
food: "番茄炒鸡蛋"
},
methods: {
doIt: function () {
alert("做It")
},
changeFood: function () {
this.food += "好吃!"
}
}
})
</script>

v-cloak指令(没有值):

  1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
  2.使用v-cloak可以解决网速慢时页面展示出的大括号xxx大括号的问题

v-once指令:

1.v-once所在节点在初次动态渲染后,就视为静态内容了
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能

v-pre指令:

1.跳过其所在结点的编译过程
2.可利用它跳过,没有使用指令语法、没有使用插值语法的节点,会加快编译

v-show指令

 写法:v-show='表达式'

v-show指令作用是:根据真假切换元素的显示状态
原理是修改元素的display,实现显示和隐藏
指令后面的内容,最终都会解析为布尔值
值为true元素显示,值为false元素隐藏

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">
<input type="button" value="切换显示状态" @click="changeIsshow">
<img v-show="isShow" src="profile.jpg" alt="">
<img v-show="age>=18" src="profile.jpg" alt="">
<input type="button" value="更改年龄" @click="addAge">
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
isShow: false,
age: 17
},
methods: {
changeIsshow: function () {
this.isShow = !this.isShow;
},
addAge: function () {
this.age++;
console.log(this.age)
}
}
})

v-if指令

1.v-if='表达式'
2.v-else-if='表达式'
3.v-else='表达式'

注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”
v-if指令作用是:根据表达式的真假切换元素显示状态
本质是通过操纵dom元素来切换显示状态
表达式的值为true,元素存在于dom树中,为false,从dom树中移除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
<input type="button" value="切换显示" @click="toggleIsShow">
<p v-if="isShow">黑马程序员</p>
<p v-show="isShow">黑马程序员 - v-show修饰</p>
<h2 v-if="temperature>=35">热死了</h2>
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
isShow: false,
temperature: 40
},
methods: {
toggleIsShow: function () {
this.isShow = !this.isShow;
}
}
})
</script>

template语法(模板)使用

当v-if条件成立时 template会在页面生成后自动删除

1
2
3
4
5
<template v-if="n===1">
<h2>你好</h2>
<h2>北京</h2>
<h2>南京</h2>
</template>

v-bind属性

v-bind指令的作用是:为元素绑定属性,数据只能从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
29
30
<style>
.active {
border: 1px solid red;
}
</style>

<body>
<div id="app">
<img v-bind:src="imgSrc" alt="">
<br>
<!-- v-vlind可简写 -->
<img :src="imgSrc" alt="" :title="imgTitle+'!!!'" :class="{active:isActive}" @click="toggleActive">

</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
imgSrc: "profile.jpg",
imgTitle: "黑马",
isActive: false
},
methods: {
toggleActive: function () {
this.isActive = !this.isActive;
}
}
})
</script>

绑定class事件

字符串写法,适用于:样式的类名不确定,需要动态指定
数组写法,适用于:要绑定的样式个数不确定、名字也不确定
对象写法:适用于:要绑定的央视个数确定,名字也确定,但要动态决定用不用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body>
<div class="basic" :class="mood" @click="changeMood"></div>
<div class="basic" :class="classArr" @click="changeMood"></div>
<div class="basic" :class="classObj" @click="changeMood"></div>
<script src="vue.js"></script>
<script>
const vm=new Vue({
el:'',
data:{
name:'',
mood:'',
classArr:['class01','class02','class03'],
classObj:{
class01:false,
class02:false
}
}
})
</script>

style样式

:style=’{fontSize:xxx}’其中xxx是动态值
:style=’[a,b]’其中a,b是样式对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="basic" :style='styleObi'>{{}}</div>
<script>
const vm=new Vue(
{
el:'#root',
data:{
name:'',
styleObj:{
fontSize:'40px',
color:'red',
}
}
}
)
</script>

v-model指令

双向绑定,数据不仅能从data流向页面,还可以从页面流向data
一般用在表单元素上(input、select)
v-model:value 可以简写为v-model,因为v-model默认收集的就是value

1
2
3
4
5
<input type="text" v-model="name">
//相当于
<input type="text" v-model:value="name">
//如下代码错误
<h2 v-model:x="name">你好啊</h2>

v-for指令

v-for指令的作用是:根据数据生成列表结构
v-for不仅可以遍历数组也可以遍历对象字符串
数组经常和v-for结合使用
语法是(item,index)in数据
item和index可以结合其他指令一起使用

key的作用和原理

1.虚拟DOM中key的作用
key是虚拟DOM对象标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【虚拟DOM】,随后Vue进行【新的虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比原则:
(1)旧的虚拟DOM中找到了与新虚拟DOM相同的key:
1.若虚拟DOM中内容没变,直接使用之前的真实DOM
2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
(2)旧的虚拟DOM中未找到与新虚拟DOM相同的key
3.用index作为key可能引发的问题:
1.若对数据进行:逆序添加、逆序删除:
会产生没有必要的真实DOM更新==>界面效果没问题,但效率低
2.若结构还包括输入类的DOM:
会产生错误DOM更新==>界面有问题
4.开发中如何选择key?
1.最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值

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
  <div id="app">
<input type="button" value="添加数据" @click="add">
<input type="button" value="移除数据" @click="remove">
<ul>
<li v-for="(it,index) in arr">
<!-- it可以用其它英文代替 -->
{{ index+1 }}HtuPengyuyan:{{ it }}
</li>
</ul>
<h2 v-for="item in food" v-bind:title="item.name">
{{item.name}}
</h2>
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
arr: ["北京", "上海", "广州", "深圳"],
food: [
{ name: "西兰花" },
{ name: "西红柿" }
]
},
methods: {
add: function () {
this.food.push({ name: "黄瓜" })
},
remove: function () {
this.food.shift();
}
}
})
</script>
> 收集表单数据
若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value的值。
账号:<input type='text' v-model.trim="userInfo.account"><br><br/>
1
若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
男:<input type="radio" name="sex" v-model="userInfo.sex" value="male"> 女:<input type="radio" name="sex" v-model="userInfo.sex" value="female"><br/><br>
1
2
若:<input type="checkbox"/>
1.没有配置input的value属性,那么收集的就是checked(勾选or未勾选,是布尔值)

阅读并接受

1
2
3
4
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选or未勾选,是布尔值)

(2)v-model的初始值是数组,那么收集的就是value组成的数组

爱好:
学习
打游戏
吃饭

1
2
3
4
备注:v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效数字
trim:输入首尾空格要过滤

v-on补充

事件绑定的方法写成函数调用的形式,可以传入自定义参数
定义方法时需要定义形参来接收传入的实参
事件的后面跟上.修饰符可以对事件进行限制
.enter可以限制触发的按键为回车

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<input type="button" value="点击" @click="doIt(666,'老铁')">
<input type="text" @keyup.enter="sayHi">
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
methods: {
doIt: function (p1, p2) {
console.log(p1);
console.log(p2)
},
sayHi: function () {
alert("吃了没")
}
}
})
</script>

v-model指令

v-model指令的作用是便携的设置和获取表单元素的值
绑定的数据会和表单元素值相关联
绑定的数据⬅➡相关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="app">
<input type="button" value="修改message" @click="setM">
<input type="text" v-model="message" @keyup.enter="getM">
<h2>{{ message }}</h2>
</div>
<script src="vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
message: "黑马程序员"
},
methods: {
getM: function () {
alert(this.message);
},
setM: function () {
this.message = "帅气"
}
}
})
</script>

自定义指令

定义语法:
1.局部指令:

1
2
3
new Vue({                                     new Vue({
directives:{指令名:配置对象} 或 directives(指令名:回调函数)
}) })

2.全局质量:

1
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名),回调函数

配置对象中常用的三个回调:
1.bind:指令与元素成功绑定时调用
2.inserted:指令所在元素被插入页面时调用
3.update:指令所在模板结构被重新解析时调用
备注:
1.指令定义时不加v-,但使用时要加v-
2.指令名如果时多个单词,要使用kebab-case明明方式,不要用cameCase命名

1
2
3
4
5
6
7
8
9
10
11
12
Vue.directive('fbind',{
bind(element,binding){
//主要用到binding里的value值
element.value=binding.value
},
inserted(element,binding){
element.focus()
},
update{
element.value=binding.value
},
})

过滤器:

定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
语法:
1.注册过滤器:Vue.filter(name,callback)或new Vue(filter:{})
2.使用过滤器: xxx | 过滤器名 或 v-bind:属性=”xxx | 过滤器名”
备注:
1.过滤器也可以接受额外参数、多个过滤器也可以串联
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
<div id="root">
<h2>显示格式化后的事件</h2>
//计算属性实现
<h3>现在是:{{fmtTime}}</h3>
//methods实现
<h3>现在是:{{getFmtTime()}}</h3>
//过滤器实现
<h3>现在是{{time | timeFormater}}</h3>
//过滤器实现(传参)
<h3>现在是{{time | timeFormater('YYYY_MM__mySlice')}}</h3>
<script>
new Vue({
el:"#root",
data:{
time:
},
computed:{
fmtTime(){
return datjs(this.time.format(YYYY-MM-DD-HH:mm:ss))
//format格式化
}
},
methods{
getFmtTime(){
return datjs(this.time.format(YYYY-MM-DD-HH:mm:ss))
}
},
filiters:{
timeFormater(value){
return datjs(this.time.format(YYYY-MM-DD-HH:mm:ss))
}
}
})
</script>

生命周期:

1.又名:生命周期回调函数、生命周期函数、生命周期钩子
2.是什么:Vue在关键时刻帮我们调用的一些特殊名称函数
3.生命周期函数的名字不可更改,但函数的具体内容时程序员根据需求编写的
4.生命周期函数中的this指向时vm 或 组件实例对象

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
<title>分析生命周期</title>
<script type="text/javascript" src="../js/vue.js"></script>

<div id="root" :x="n">
<h2 v-text="n"></h2>
<h2>当前的n值是:{{ n }}</h2>
<button @click="add">点我n+1</button>
<button @click="bye">点我销毁vm</button>
</div>

<script type="text/javascript">
Vue.config.productionTip = false

new Vue({
el: '#root',
// template:`
// <div>
// <h2>当前的n值是:{{n}}</h2>
// <button @click="add">点我n+1</button>
// </div>
// `,
data: {
n: 1
},
methods: {
add() { console.log('add')
this.n++
},
bye() {
console.log('bye')
this.$destroy()
}
},
watch: {
n() {
console.log('n变了')
}
},
beforeCreate() {console.log('beforeCreate')},
created() {console.log('created')},
beforeMount() {console.log('beforeMount')},
mounted() {console.log('mounted')},
beforeUpdate() {console.log('beforeUpdate')},
updated() {console.log('updated')},
beforeDestroy() {console.log('beforeDestroy')},
destroyed() {console.log('destroyed')},
})
</script>

总结

常用的生命周期钩子:
1.mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
2.beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息
2.销毁后自定义事件会失效,但原生DOM依然有效、
3.一般不会再beforeDestroy操作数据,因为即使操作数据,也不会再触发更新流程了

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
<title>引出生命周期</title>
<script type="text/javascript" src="../js/vue.js"></script>

<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
<button @click="opacity = 1">透明度设置为1</button>
<button @click="stop">点我停止变换</button>
</div>

<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
opacity: 1
},
methods: {
stop() {
this.$destroy()
}
},
// Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted() {
console.log('mounted', this)
this.timer = setInterval(() => {
console.log('setInterval')
this.opacity -= 0.01
if (this.opacity <= 0) this.opacity = 1
}, 16)
},
beforeDestroy() {
clearInterval(this.timer)
console.log('vm即将驾鹤西游了')
},
})
</script>

Vue组件化编程

模块

  1. 理解:向外提供特定的js程序,一般就是一个js文件
  2. 为什么:js文件很多很复杂
  3. 作用:复用、简化js的编写,提高js运行效率
    组件
  4. 定义:用来实现局部功能的代码和资源的集合
  5. 为什么:一个界面的功能很复杂
  6. 作用:复用编码、简化项目编写,提高运行效率
    模块化
    当应用中的js豆一木块来编写的,那这个应用就是一个模块化的应用
    组件化
    当应用中的功能都是多组件的方式编写的,那这个应用就是一个组件化的应用

非单文件组件

非单文件组件:一个文件中包含有n个组件
单文件组件:一个文件中只包含有1个组件
#####基本使用
1.定义组件
使用Vue.extend(options)常见,其中options和new Vue(options)时传入的options几乎一样,但也有点区别

  1. el不要写,因为最终所有的组件都要经过一个vm的管理,由vm中的el才决定服务哪个容器
  2. data必须写成函数,避免组件被复用时,数据存在引用关系
    1
    2
    3
    4
    5
    6
    data() {
    return {
    studentName: '张三',
    age: 18
    }
    }
    2.注册组件
  3. 局部注册:new Vue()的时候opyions传入compoents选项
  4. 全局注册:Vue.component(’组件名’,组件)
    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
    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
    <title>基本使用</title>
    <script type="text/javascript" src="../js/vue.js"></script>

    <div id="root">
    <h2>{{msg}}</h2><hr>
    <!-- 第三步:编写组件标签 -->
    <school></school><hr>
    <student></student><hr>
    <hello></hello><hr>
    </div>

    <div id="root2">
    <hello></hello>
    </div>

    <script type="text/javascript">
    Vue.config.productionTip = false

    //第一步:创建school组件
    const school = Vue.extend({
    // el:'#root', //组件定义时,一定不要写el配置项,
    // 因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器
    template: `
    <div class="demo">
    <h3>学校名称:{{schoolName}}</h3>
    <h3>学校地址:{{address}}</h3>
    <button @click="showName">点我提示学校名</button>
    </div>
    `,
    data() {
    return {
    schoolName: '尚硅谷',
    address: '北京昌平'
    }
    },
    methods: {
    showName() {
    alert(this.schoolName)
    }
    },
    })

    //第一步:创建student组件
    const student = Vue.extend({
    template: `
    <div>
    <h3>学生姓名:{{studentName}}</h3>
    <h3>学生年龄:{{age}}</h3>
    </div>
    `,
    data() {
    return {
    studentName: '张三',
    age: 18
    }
    }
    })

    //第一步:创建hello组件
    const hello = Vue.extend({
    template: `
    <div>
    <h3>你好啊!{{name}}</h3>
    </div>
    `,
    data() {
    return {
    name: 'cess'
    }
    }
    })

    //第二步:全局注册组件
    Vue.component('hello', hello)

    //创建vm
    new Vue({
    el: '#root',
    data: {
    msg: '你好啊!'
    },
    //第二步:注册组件(局部注册)
    components: {
    school,
    student
    }
    })

    new Vue({
    el: '#root2',
    })
    </script>

组件注意事项

关于组件名

1.一个单词组成

  1. 第一种写法(首字母小写):school
  2. 第二种写法(首字母大写):School
    2.多个单词组成
  3. 第一种写法(kebab-case,命名):my-school
  4. 第二种写法(CamelCase命名):MySchool(需要Vue脚手架支持)!Vue官方推荐
    3.备注
  5. 组件名尽可能回避html中已有的元素名称,例如:好、H2都不行
  6. 可以使用name配置项指定组件在开发者工具中呈现的名字
关于组件的标签
  1. 第一种写法:
  2. 第二种写法:(需要Vue脚手架的支持)
  3. 备注:不使用脚手架时,会导致后续组件不能渲染
    一个简写方式:const school=Vue.extend(options)可简写为 const school=options,因为父组件components引入的时候会自动创建

组件的嵌套

VueComponent

  1. school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,而是Vue.extend()生成的
  2. 我么只需要写或,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的new VueComponent(options)
  3. 每次调用Vue.extend,返回的都是一个全新的VueCompoent,即不同的组件是不同的对象
  4. 关于this指向
  5. 组件配置中data 函数、methods中的函数、watch中的函数、computed中的函数它们的this均是VueComponent实例对象
  6. newVue(options)配置中:data函数、watch中的函数、computed中的函数它们的this均是Vue实例对象,即vm
  7. VueComponent的实例对象,以后简称vc(组件实例对象)Vue的实例对象,以后简称为vm

单文件组件

School.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
<template>
<div id='Demo'>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
</template>

<script>
export default {
name:'School',
data() {
return {
name:'UESTC',
address:'成都'
}
},
methods: {
showName(){
alert(this.name)
}
},
}
</script>

<style>
#Demo{
background: orange;
}
</style>

Student.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
</template>

<script>
export default {
name:'Student',
data() {
return {
name:'cess',
age:20
}
},
}
</script>

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
<School></School>
<Student></Student>
</div>
</template>

<script>
import School from './School.vue'
import Student from './Student.vue'

export default {
name:'App',
components:{
School,
Student
}
}
</script>

main.js

1
2
3
4
5
6
7
import App from './App.vue'

new Vue({
template:`<App></App>`,
el:'#root',
components:{App}
})

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!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>单文件组件练习</title>
</head>
<body>
<div id="root"></div>
<script src="../../js/vue.js"></script>
<script src="./main.js"></script>
</body>
</html>

VueCLi初始化脚手架

初始化脚手架

说明

  1. Vue脚手架是Vue官方提供的标准化开发工具(开发平台)
  2. 最新版本是4.x
  3. 文档Vue CLi
    具体步骤
  4. 如果下载缓慢请配置npm淘宝镜像npm comfig registry http://registry.npm.taobao.org
  5. 全局安装@vue/cli npm install -g @vue/cli
  6. 切换到创建项目的目录,使用命令创建项目vue create xxx
  7. 选择使用vue的版本
  8. 启动项目npm run serve
  9. 打包项目npm run bulid
  10. 暂停项目ctrl+c

脚手架文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.文件目录
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源
│ │ └── logo.png
│ │── component: 存放组件
│ │ └── HelloWorld.vue
│ │── App.vue: 汇总所有组件
│ └── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
└── package-lock.json: 包版本控制文件
render函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
el:'#app',
// render函数功能:将App组件放入容器中
// 简写形式
render: h => h(App),
// 完整形式
// render(createElement){
// return createElement(App)
// }
})

vue.config.js配置文件

使用vue.config.js可以对脚手架进行个性化定制,和package.json同级目录

1
2
3
4
5
6
7
8
module.exports = {
pages: {
index: {
entry: 'src/index/main.js' // 入口
}
},
lineOnSave: false // 关闭语法检查
}

ref属性

ref被用来给元素或子组件注册引用信息(id的替代者)

  1. 应用在html标签上获取的是真实DOM元素,应用在组件标签上获取的是组件实例对象vc
  2. 使用方式
    1. 打表示:
      1
      <h1 ref="xxx"></h1>或<School ref='xxx'><School>
    2. 获取:
      1
      this.$ref.xxx
      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>
      <div>
      <h1 v-text="msg" ref="title"></h1>
      <button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
      <School ref="sch"/>
      </div>
      </template>

      <script>
      import School from './components/School'

      export default {
      name:'App',
      components:{ School },
      data() {
      return {
      msg:'欢迎学习Vue!'
      }
      },
      methods: {
      showDOM(){
      console.log(this.$refs.title) // 真实DOM元素
      console.log(this.$refs.btn) // 真实DOM元素
      console.log(this.$refs.sch) // School组件的实例对象(vc)
      }
      },
      }
      </script>

props配置项

props 让组件接收外部传过来的数据

  1. 传递数据,通过v-bind使得里面的18是数字
  2. 接收数据
    1. 第一种方式(只接受)
      1
      props::['name','age']
    2. 第二种方式(限制类型)
      1
      props::[name:String,age:Number]
    3. 第三种方式(限制类型、限制必要性、指定默认值)
      1
      2
      3
      4
      5
      6
      7
         props: {
      name: {
      type: String, // 类型
      required: true,// 必要性
      default: 'cess'// 默认值
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中,然后去修改data中的数据

      ### mixin混入
      1. 功能:可以把多个组件共用的配置提取成一个混入对象
      2. 使用方式
      1. 定义混入
      ```javascript
      const mixin = {
      data() {....},
      methods: {....}
      ....
      }
  3. 使用混入
  4. 全局混入
    1
    Vue.mixin(xxx)
    2.局部混入
    1
    mixins['xxx']
    备注
  5. 组件和混入对象含同名选项时,这些选项将以恰当的方式进行“合并”,在发生冲突时组件优先
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    var mixin = {
    data: function () {
    return {
    message: 'hello',
    foo: 'abc'
    }
    }
    }

    new Vue({
    mixins: [mixin],
    data () {
    return {
    message: 'goodbye',
    bar: 'def'
    }
    },
    created () {
    console.log(this.$data)
    // => { message: "goodbye", foo: "abc", bar: "def" }
    }
    })
  6. 同名生命周期钩子将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var mixin = {
    created () {
    console.log('混入对象的钩子被调用')
    }
    }

    new Vue({
    mixins: [mixin],
    created () {
    console.log('组件钩子被调用')
    }
    })

    // => "混入对象的钩子被调用"
    // => "组件钩子被调用"

plugin插件

  1. 功能:用于增强Vue
  2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据
  3. 定义插件(见下src/plugin.js)
  4. 使用插件:Vue.use()
    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
    export default {
    install(Vue,x,y,z){
    console.log(x,y,z)
    //全局过滤器
    Vue.filter('mySlice', function(value){return value.slice(0,4)})

    //定义全局指令
    Vue.directive('fbind',{
    //指令与元素成功绑定时(一上来)
    bind(element,binding){element.value = binding.value},
    //指令所在元素被插入页面时
    inserted(element,binding){element.focus()},
    //指令所在的模板被重新解析时
    update(element,binding){element.value = binding.value}
    })

    //定义混入
    Vue.mixin({
    data() {return {x:100,y:200}},
    })

    //给Vue原型上添加一个方法(vm和vc就都能用了)
    Vue.prototype.hello = ()=>{alert('你好啊')}
    }
    }
    main.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import Vue from 'vue'
    import App from './App.vue'
    import plugins from './plugins' // 引入插件

    Vue.config.productionTip = false

    Vue.use(plugins,1,2,3) // 应用(使用)插件

    new Vue({
    el:'#app',
    render: h => h(App)
    })

scoped样式

  1. 作用:让样式在局部生效,防止冲突
  2. 写法: