Vue框架基础
认识Vue:
- 需要创建一个Vue实例,传入一个配置对象;
- 需要准备一个DOM元素当作root容器(与react类似),root容器中的代码依然符合html规范,不过混入了一些Vue语法;
- root容器里的代码被称为【Vue模板】;
- Vue实例与容器一一对应;
- 真实开发中一般只有一个Vue实例,配合组件一起使用;
- {{xxx}}语法只能写js表达式,而且可以自动读取data中的所有属性;
- 一旦data中的数据发生改变,那么页面中使用到其数据的地方也会自动更新;(react需要使用setData);
Vue模板语法:
- 插值语法: 功能:用于解析标签体内容; 用法:{{xxx}} xxx ==> js表达式,可以读取data中的所有属性;
-
指令语法: 功能:用于解析标签(eg. 标签属性、标签体内容、绑定事件...)
eg.
v-bind:href=“xxx”
or 简写:href="xxx"
,xxx写js表达式;
Vue数据绑定(2种):
- 单向绑定
v-bind
:数据只能从data流向页面;
eg.
<input type="text" :value="name"/>
<script>
Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
name:'greeny'
}
})
</script>
- 双向绑定
v-model
:数据从data流向页面,也可以从页面流向data;
实现原理:value与input事件实现,可以通过v-model
实现父子组件数据同步;
备注:
- 双向绑定一般应用在表单类元素上(eg. input、select);
v-model:value
可以简写为 v-model (因为v-model默认收集value值);
eg.
<input type="text" v-model="name"/>
<script>
Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
name:'greeny'
}
})
</script>
data与el的写法:
- el:2 种:
(1)new Vue 实例时配置el属性;
(2)先创建Vue实例,后通过实例vm.$mount("#root")指定el的值;
- data :2种:
(1)对象式
data:{ name:"xxx" }
(2)函数式
data(){ return { name:"xxx" } }
原则:
不要写箭头函数,this指向会丢失,不会再是Vue实例;
Vue中的MVVM:
MVVM模型:
- M 模型 (Model) : data中的数据
- V 视图 (View) : 模板代码
- VM 视图模型 (ViewModel) : Vue 实例(通常为vm)
Vue中的MVVM:
- data中的所有属性,最后都出现在实例vm上;
- 实例vm上所有的属性及Vue原型上所有属性,在Vue模板中都可以直接使用;
eg.
<div id="root">
<h1>学校名称:{{name}}</h1>
<h1>学校地址:{{address}}</h1>
<!--
<h1>测试一下2:{{$options}}</h1>
<h1>测试一下3:{{$emit}}</h1>
<h1>测试一下4:{{_c}}</h1>
-->
</div>
<script type="text/javascript">
Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
name:'greeny',
address:'广州',
}
})
console.log(vm)
</script>
Vue数据代理:
Object.defineproperty
方法
简书:深入浅出Object.defineProperty()
用法:
Object.defineproperty(obj, prop, desc)
obj:需要定义属性的当前对象
prop:当前需要定义的属性名
desc:属性描述符
注意,如果描述符中的某些属性被省略,会使用以下默认规则:
eg.
<script type="text/javascript" >
let number = 18
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
// value:18,
// enumerable:true, //控制属性是否可以枚举,默认值是false
// writable:true, //控制属性是否可以被修改,默认值是false
// configurable:true //控制属性是否可以被删除,默认值是false
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get(){
console.log('有人读取age属性了')
return number
},
//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
console.log('有人修改了age属性,且值是',value)
number = value
}
})
// console.log(Object.keys(person))
console.log(person)
</script>
数据代理:
通过一个对象代理对另一个对象中属性的操作(读/写)
eg.
<script type="text/javascript" >
let obj = {x:100} //对象代理
let obj2 = {y:200} //被代理的对象,其x属性值被obj代理操作
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(value){
obj.x = value
}
})
</script>
Vue中的数据代理
通过vm对象来代理data对象中属性的操作(读/写);
基本原理:
- 通过Object.defineProperty()把data对象中所有属性添加到vm实例身上;
- 给每个添加到vm上的属性添加getter和setter;
- 在getter/setter内部操作(读/写)data中对应的属性;
事件处理v-on
基本使用
- 使用
v-on:事件名
或 @xxx 绑定事件;
- 事件回调需要配置在methods对象中,最终挂载在vm上;
- methods中配置的函数不能使用箭头函数,要保证this不会丢失;
- methods中配置得到函数都是被Vue管理的函数,所以this指向为vm 或 组件实例;
@click="demo"
和@click="demo($event)"
效果一样,但后者可以传参;
事件修饰符
Vue提供的事件修饰符:
- prevent:阻止默认事件(常用);
- stop:阻止事件冒泡(常用);
- once:事件只触发一次(常用);
- capture:使用事件的捕获模式;
- self:只有event.target是当前操作的元素时才触发事件;
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
eg.
<div id="root">
<!-- 阻止默认事件(常用) -->
<a href="http://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>
<!-- 阻止事件冒泡(常用) -->
<div @click="showInfo">
<button @click.stop="showInfo">点我提示信息</button>
<!-- 修饰符可以连续写 -->
<!-- <a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a> -->
</div>
<!-- 事件只触发一次(常用) -->
<button @click.once="showInfo">点我提示信息</button>
<!-- 使用事件的捕获模式 -->
<div @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 只有event.target是当前操作的元素时才触发事件; -->
<div @click.self="showInfo">
<button @click="showInfo">点我提示信息</button>
</div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
},
methods:{
showInfo(e){
alert('同学你好!')
// console.log(e.target)
},
showMsg(msg){
console.log(msg)
},
}
})
</script>
键盘事件
- Vue中常用的按键别名(与真正的按键key值不一致)
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right
- 未提供的按键可以用按键原始的key值绑定,但注意要转为
kebab-case
(短横线命名) - 系统修饰键(特殊):
ctrl、alt、shift、meta
- 配合keyup使用:按下修饰键的同时,在按下其他键随后释放其他键时间才会触发;
- 配合keydown使用:正常触发事件;
Vue.config.keyCodes.自定义键名 = 键码
,可以定制按键别名;
计算属性computed
对于任何复杂逻辑,你都应当使用计算属性。——官网
- 定义:不存在data属性中,通过已有的属性计算得来的属性;
- 原理:底层借助了Object.defineproperty方法提供的getter和setter;
- 对比:与methods相比,内部有缓存机制(若没有改变可以被复用),效率高,调试方便;
- get方法
作用:当计算属性被读取时,get会被调用,且返回值作为fullName的值;
调用:a.初次读取fullName时;b.所依赖的数据发生变化时;
- set方法
作用:计算属性若要修改,需要写set方法去响应修改,且set中要引起依赖的数据发生改变;
调用:当fullName被修改时;
注意:
计算属性最终会出现在vm实例身上,和data中的属性一样直接读取即可;
<div id="root">
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
测试:<input type="text" v-model="x"> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
firtName:'张',
lastName:'三'
},
computed:{
// 完整写法
fullName:{
get(){
consle.log('get被调用')
return this.firtName + '-' + this.lastName
}
set(value){ //value 全名
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
},
//简写 只读不改
fullName1(){
console.log('get被调用')
return this.firstName + '-' + this.lastName
}
}
})
<script/>
侦听属性watch
- 当被监视的属性变化时,回调函数会自动调用,执行函数中的代码;
- 监视的属性必须存在才能被监视;
- 两种写法:
- 和data等属性一样在配置对象中传入watch配置;
- 通过vm.$watch()方法监视;
- 方法内的配置:
immediate: true
初始化时让handler调用一下,默认值为false;
handler(newValue, oldValue){}
简写可以不用写
deep: true
深度检测
// 写法一
watch:{
isHot:{
// immediate:true, //初始化时让handler调用一下
// deep:true,//深度监视
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
},
//简写
/* isHot(newValue, oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
} */
}
// 写法二
vm.$watch('isHot',{
immediate:true,
handler(newValue, oldValue){
console.log('监听的属性被修改', newValue, oldValue)
}
})
//简写
/* vm.$watch('isHot',(newValue,oldValue)=>{
console.log('isHot被修改了',newValue,oldValue,this)
}) */
computed 和 watch 的对比 
- computed能完成的功能,watch也能实现;
- watch能够进行异步操作,但computed不可以;
两者使用原则:
- 不能用箭头函数形式;
- 不被Vue管理的方法(定时器的回调,Ajax的回调,promise的回调)最好用箭头函数写法,保证this的指向为vm实例或组件实例对象;
绑定样式
class样式
写法 class="xxx" xxx可以为字符串/对象/数组;
字符串适用于类名不确定要动态获取;
对象适用于绑定多个样式,个数确定,名字确定,但不确定是否使用;
数组适用于绑定多个样式,个数不确定,名字也不确定;
style样式
:style="{fontSize: xxx}"
xxx 为动态值;
:style-"[a,b]"
其中,a和b为样式对象;
条件渲染
v-if
指令
写法:v-if
= "表达式" 、v-else-if
= "表达式" 、v-else
= "表达式" ;
适用于:切换频率低的场景;
特点:不展示的DOM元素直接被移除;
注意:v-if
和v-else-if
、v-else
可以搭配使用,但结构不能被打断;
v-show
指令
写法:v-show
= "表达式"
适用于:切换频率较高的场景;
特点:不展示的DOM元素未被移除,仅仅是通过样式display=none
隐藏;
备注: 使用 v-if
的元素可能无法被获取,但使用 v-show
的元素一定能被找到;
<div id="root">
<!-- 使用v-show做条件渲染 -->
<h2 v-show="false">欢迎{{name}}</h2>
<h2 v-show="1 === 1">欢迎{{name}}</h2>
<!-- 使用v-if做条件渲染 -->
<h2 v-if="false">欢迎{{name}}</h2>
<h2 v-if="1 === 1">欢迎{{name}}</h2>
<!-- v-else和v-else-if -->
<!-- <div v-if="n === 1">Angular</div>
<div v-else-if="n === 2">React</div>
<div v-else-if="n === 3">Vue</div>
<div v-else>哈哈</div> -->
<!-- v-if 与 template 搭配-->
<!-- 可以将多个结构使用一个v-if指令,且template不会被解析为DOM结构-->
<template v-if="n === 1">
<h2>你好</h2
<h2>北京</h2>
</template>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
name:'greeny',
n:0
}
})
</script>
列表渲染
v-for
指令
- 用于展示列表数据;
- 语法:
v-for = "( item,index ) in obj" :key="id"
- 可遍历类型:数组、对象、字符串(少)、指定次数(少);
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<ul>
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}
</li>
</ul>
<!-- 遍历对象 -->
<h2>汽车信息(遍历对象)</h2>
<ul>
<li v-for="(value,k) in car" :key="k">
{{k}}-{{value}}
</li>
</ul>
<!-- 遍历字符串 -->
<h2>测试遍历字符串(用得少)</h2>
<ul>
<li v-for="(char,index) in str" :key="index">
{{char}}-{{index}}
</li>
</ul>
<!-- 遍历指定次数 -->
<h2>测试遍历指定次数(用得少)</h2>
<ul>
<li v-for="(number,index) in 5" :key="index">
{{index}}-{{number}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20}
],
car:{
name:'奥迪A8',
price:'70万',
color:'黑色'
},
str:'hello'
}
})
</script>
key的作用原理
- 虚拟DOM中的key作用:
key为虚拟DOM对象的唯一标识,当数据发生变化时,Vue会根据变化的数据生成新的虚拟DOM,随后Vue进行新,旧虚拟DOM的差异比较;
对比规则:
- 旧虚拟DOM中找到与新虚拟DOM相同的key:
①若虚拟DOM中内容没变,直接使用之前的真实DOM;
②若虚拟DOM中内容变了,生成新的真实DOM,随后替换掉页面之前的真实DOM; - 旧虚拟DOM中未找到与新虚拟DOM相同的key:
创建新的真实DOM,随后渲染到页面; 备注: 对比的虚拟DOM体内容:标签体中的属性值 <input type="text" .../>
- 旧虚拟DOM中找到与新虚拟DOM相同的key:
- 用
index
作为key
的问题:
(1) 若对数据进行:逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实DOM的更新 ====> 页面渲染没有问题,但是效率低;
(2) 如果结构中包含输入类的DOM,会产生DOM的错误更新 ====> 页面渲染有问题;
- 开发中的key定义:
(1) 最好使用每条数据的唯一标识作为key,eg. id、手机号、身份证号、学号;
(2) 如果不存在数据的逆序添加、删除等破坏顺序的操作,仅用于渲染列表展示则使用index作为key没有问题;
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<button @click.once="add">添加一个老刘</button>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}-{{p.age}}
<input type="text">
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20}
]
},
methods: {
add(){
const p = {id:'004',name:'老刘',age:40}
this.persons.unshift(p)
}
},
})
</script>
模拟数据检测(修改操作的监测)
依靠Object.defineProperty()
方法
<script type="text/javascript" >
let data = {
name:'greeny',
address:'广州'
}
// 创建一个监视的实例对象,用于监视data中的属性变化
const obs = new Observer(data)
console.log(obs)
//准备一个vm实例
let vm = {}
vm._data = data = obs
// 执行前,将 vm 的引用 和 data 一致 都是 vm的指向
// 内存中创建新的对象为obs
// data = obs : 将data中的指向改为新的obs地址
// vm._data = data : 此时data已经指向新对象(与vm一致),但vm._data的vm没有改变
// 给vm添加一个属性_data,内容为obs(此刻的data)
// 原对象vm添加了_data属性,data指向obs
function Observer(obj){
//汇总监视对象的所有属性形成一个数组
const keys = Object.keys(obj)
//遍历
keys.forEach((k)=>{
Object.defineProperty(this, k, {
get(){
return obj[k]
}
set(val){
console.log(`${k}被修改`)
obj[k] = val
}
})
})
}
</script>
Vue.set 的使用
<div id="root">
<h1>学校信息</h1>
<h2>学校名称:{{school.name}}</h2>
<h2>学校地址:{{school.address}}</h2>
<h2>校长是:{{school.leader}}</h2>
<hr/>
<h1>学生信息</h1>
<button @click="addSex">添加一个性别属性,默认值是男</button>
<h2>姓名:{{student.name}}</h2>
<h2 v-if="student.sex">性别:{{student.sex}}</h2>
<h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
<h2>朋友们</h2>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}--{{f.age}}
</li>
</ul>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
school:{
name:'xxx大学',
address:'广州',
},
student:{
name:'tom',
age:{
realAge:40,
fakeAge:18
},
friends:[
{name:'jerry',age:35},
{name:'tomy',age:36}
]
}
},
methods:{
addSex(){
// Vue.set(this.student,'sex','男')
this.$set(this.student, 'sex', '男')
}
}
})
</script>
Vue数据监测原理:
- Vue会监视data中所有层次的数据;
-
监测对象中的数据:
通过setter实现监视,且需要在new 实例的时候传入监测的数据;
(1) 对象中后追加的属性,Vue默认不做响应式处理;
(2) 后添加的属性需要做响应式,需使用特定API:Vue.set(target, propertyName/index, value)
或
vm.$set(target, propertyName/index, value)
-
监测数组中的数据:
通过包裹数组更新元素的方法实现,本质做了以下两件事:
(1) 调用原生对应的方法对数组进行更新;
(2) 重新解析模板,进而更新页面;
- 在Vue修改数组中某个元素的数据时一定要使用如下方法,才能被Vue监测到:
(1) 使用这些API: push()、pop()、shift()、unshift()、splice()、sort()、reverse()
(2)Vue.set()
或vm.$set()
注意:
Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!
表单数据收集
若<input type="text"/>
,则v-model收集的是value值,用户输入的就是value值;
若<input type="radio"/>
,则v-model收集的是value值,且要给标签配置value;
若<input type="checkbox"/>
:
- 没有配置input的value属性,收集的是checked值[true/false];
- 配置了input的value属性:
(1)v-model的初始值是非数组,收集的是checked[true/false];
(2)v-model的初始值是数组,收集的是value组成的数组
备注: v-model的 3 个修饰符:
lazy
失去焦点再收集
number
输入字符串转为有效数字
trim
输入首尾空格过滤【中间的不过滤】
过滤器
对要显示的数据进行特定格式化后再显示(适用于一些简单的逻辑处理)
语法:
- 注册过滤器:
Vue.filter(name, callback)
【全局过滤器】或new Vue{filters:{}}
【局部过滤器】;
- 使用过滤器:
{{xxx | 过滤器名}}
或v-bind:属性 = "xxx | 过滤器名"
;
备注:
- 过滤器也可以接收额外参数、多个过滤器可以串联;
- 没有改变原本的数据,是产生新的对应的数据;
eg.
<!-- html标签内,引用一下dayjs -->
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="../js/dayjs.min.js"></script>
<!-- body标签内 -->
<div id="root">
<h2>显示格式化后的时间</h2>
<!-- 计算属性实现 -->
<h3>现在是:{{fmtTime}}</h3>
<!-- methods实现 -->
<h3>现在是:{{getFmtTime()}}</h3>
<!-- 过滤器实现 -->
<h3>现在是:{{time | timeFormater}}</h3>
<!-- 过滤器实现(传参) -->
<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
<h3 :x="msg | mySlice">greeny</h3>
</div>
<div id="root2">
<h2>{{msg | mySlice}}</h2>
</div>
<!-- body标签外 -->
<script type="text/javascript">
Vue.config.productionTip = false
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
new Vue({
el:'#root',
data:{
time:1642149874736, //时间戳
msg:'你好,同学'
},
computed: {
fmtTime(){
return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
}
},
methods: {
getFmtTime(){
return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
}
},
//局部过滤器
filters:{
timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
// console.log('@',value)
return dayjs(value).format(str)
}
}
})
new Vue({
el:'#root2',
data:{
msg:'hello,nihao!'
}
})
</script>
内置指令
v-text
- 作用:向其所在的节点中渲染文本内容;
- 与插值语法区别:
v-text
会替换掉节点中的内容,插值语法{{xxx}}
不会;
v-html
- 作用:向指定的节点中渲染包含html标签结构的内容;
- 与插值语法区别:
(1)v-html
会替换掉节点中的所有内容,{{xxx}}
不会;
(2)v-html
可以识别到html结构;
- 注意:
v-html
存在安全问题
(1)在网站上动态渲染任意HTML是危险的,容易导致xss攻击;
(2)要在可信的内容上使用v-html
,不能在用户提交的内容上使用;
v-cloak
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会将这个属性删除;
- 使用css配合
v-cloak
可以解决网速慢时页面出现插值语法{{内容}}的问题;
v-once
v-once
所在节点在初次动态渲染后,就被视为静态的内容;
- 以后的数据变化不会引起
v-once
所在结构的更新,所以可以用于优化性能;
v-pre
- 跳过其所在节点的编译过程;
- 可以利用它跳过没有使用指令语法/插值语法的节点,可以优化编译;
自定义指令
自定义指定的回调函数会传入指令绑定的元素节点、以及一个binding
对象
其配置对象中的回调函数的 this指向===>window
其配置对象中常用的3个回调:
(1)bind: 指令与元素成功绑定时调用;
(2)inserted: 指令所在元素被插入页面时调用;
(3)update: 指令所在模板结构被重新解析时调用;
eg.
定义一个
v-fbind
指令,与v-bind
相似,但可以把其所绑定的input元素默认获取焦点
- 全局定义
Vue.directive(指令名称, 配置对象)
或 Vue.directive(指令名, 回调函数)
;
<div id="root">
<input type="text" v-fbind:value="n"/>
</div>
<script>
//定义全局的自定义指令
Vue.directive('fbind'),{
//指令与元素成功绑定时(一开始)
bind(element, binding){
element.value = binding.value;
},
//指令所在元素被插入页面时(页面已经存在该元素)
inserted(element, binding){
element.focus();
},
//指令所在的模板被重新解析时
update(element, binding){
element.value = binding.value;
}
}
</script>
- 局部定义
new Vue({ directives: {指令名 : 配置对象} })
或 new Vue({ directives: {指令名:回调函数 } })
<div id="root">
</div>
<script>
new Vue({
el:'#root',
data:{
n:1
},
directives:{
fbind:{
//指令与元素成功绑定时(一开始)
bind(element, binding){
element.value = binding.value;
},
//指令所在元素被插入页面时(页面已经存在该元素)
inserted(element, binding){
element.focus();
},
//指令所在的模板被重新解析时
update(element, binding){
element.value = binding.value;
}
}
}
})
</script>
Vue的生命周期
常用的生命周期钩子:
mounted
发送Ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作;
beforeDestroy
清除定时器、解绑自定义事件、取消订阅消息等收尾工作;
备注:
-
第一个生命钩子,所谓的 before Create 是在数据监测、数据代理初始化之前,并不是vm实例创建之前 ;
-
与第一个钩子对应,所谓的 created 是数据监测、数据代理初始化完成,所以可以通过vm访问到data中的数据、methods中配置的方法;
关于销毁Vue实例:
- 销毁后在Vue开发者工具中不能看到任何信息(除非有缓存);
- 销毁后自定义事件失效,但原生的DOM事件会存在依然有效;
- 一般不在
beforeDestroy
中操作数据,因为即使操作数据也无法触发更新流程;
<!-- body内 -->
<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>
<!-- body内 -->
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
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>
Vue组件
使用步骤:
-
定义组件 ( 创建组件 ) ;
使用
Vue.extend(options)
创建,其中options
和new Vue(options)
时传入的那个options
几乎一样,但也有点区别;
区别如下:
el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
备注: 使用template可以配置组件结构。
-
注册组件;
(1) 局部注册:new Vue的时候传入components选项;
(2) 全局注册:Vue.component('组件名',组件);
-
使用组件( 写组件标签 );
<Demo></Demo>
注意:
-
关于组件名:
一个单词:
demo
【首字母小写】 /Demo
【首字母大写】;多个单词:
my-demo
【kebab-case 命名】/MyDemo
【CamelCase命名】;
备注:
1. 组件名尽可能回避HTML中已有的元素名称;
2. 可以使用name配置项指定组件在开发者工具中呈现的名称;
2. 关于组件标签:
写法一: `<demo></demo>`
写法二:`<demo/>`
备注: 写法二需要使用脚手架才能处理渲染到页面上;
- 简写方式
//正常写法
const demo = Vue.extend(options)
//简写
const demo = options
关于VueComponent
组件实例本质是通过名为VueComponent
的构造函数创建的,由Vue.extend
方法生成;
部分源码:
Vue.extend = function (extendOptions) {
/*....*/
var Sub = function VueComponent (options) {
this._init(options);
};
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
/*....*/
return Sub
};
组件中的this指向 ===> 均是VueComponent
的实例对象,简称vc【与Vue的实例对象vm要区别开来】;
注意一个内置关系:
VueComponent.prototype.__proto__ === Vue.prototype
通过修改后可以让组件实例访问到Vue原型上的属性和方法;
Vue CLI 脚手架
-
main.js
文件整个项目的入口文件
-
vue.js
与vue.runtime.xxx.js
的区别(1)
vue.js
是完整版的Vue
,包含 核心功能 + 模板解析器;(2)
vue.runtime.xxx.js
是只包含核心功能; -
由于入口文件
main.js
中引用的文件不包含模板解析器,不能使用template配置项,需要通过使用render
函数接收到的createElement
函数去指定具体内容;