1、vue的实例和容器是一一对应的
2、双向数据绑定(v-model)只能应用在表单类(输入类)元素上,都有value值
3、el的两种写法
//第一种
new Vue({
el:'#root',
data:{xx:'xxx'}
})
//第二种
const v = new Vue({
el:'#root',
data:{xx:'xxx'}
})
v.$mount('root')
4、data的函数式写法中的this为vue实例对象
5、mvvm模型
-
M:模型(Model) :data中的数据
-
V:视图(View) :模板代码
-
VM:视图模型(ViewModel):Vue实例
观察发现:
-
1.data中所有的属性,最后都出现在了vm身上。
-
2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。
6、数据代理
defineProperty
:通过defineProperty添加的属性默认不可以被枚举、不可以被修改、不可以被删除
Object.defineProperty(要添加属性的对象,'属性的名称',{
value:'属性值',
enumerable:true,//控制属性是否可以枚举,默认值为false
writable:true,//控制属性是否可以被修改
configurabel:true,//控制属性是否可以被修改
)}
eg:要给添加的属性值赋值为变量
get:当有人读取Person的age值时,才会获取到,比如浏览器中的浅颜色属性,值为…,点开才能看到
set:当有人修改person的age属性时,set函数会被调用,会收到修改的具体值
let number = 18;
Object.defineProperty(Person,'get',{
get(){
return number
},
set(value){
console.log(value)
number = value;//由于age使用的是number的值,所以要修改number的值
}
)}
什么是数据代理
let obj = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(value){
obj.x = value
}
})
通过obj2可以获取到obj中的x的值,并且可以修改obj中x的值
vue中的数据代理
7、计算属性
计算属性使用的是get和set方法,现在所使用的都是计算属性的简写,将get内的方法写出,如果需要直接修改计算属性的值,则需要给计算属性写一个set方法
计算属性的get调用时间:(1)初次读取计算属性时(2)计算属性所依赖的数据发生变化时
computed:{
aa:{
set(value){
const arr = value.spilit('用什么分割计算属性所依赖的数据')
//修改计算属性所依赖的数据
},
get(){
console.log('我是get方法')
},
}
}
//简写
computed:{
aaa(){
console.log('我是get方法')
}
}
计算属性中有缓存
区分计算属性和data中的数据:计算属性不存在于vm._data
中
8、监听
watch:{
aaa:{
imediate:true,//初始化时调用handler
handler(newValue,oldValue){}
}
}
深度监听
dat(){
return {
numbers:{
a:1,
b:2
}
}
},
watch:{
//监视多级结构中某个属性的变化
"numbers.a":{
handler(){
}
},
//监视多级结构中任何一个属性的变化
numbers:{
deep:true,
handle(){}
}
}
//简写
watch:{
aaa(oldValue,newValu){}
}
computed和watch的区别
-
computed能完成的watch都能实现
-
watch可以进行异步操作,但是computed不可以
9、vue中的key
-
vue中使用key对比的是虚拟dom
-
如果循环中没有写key,默认吧index作为key
-
如果对数据进行破坏顺序的操作,不要使用index作为key,使用id作为key
vue中的key有什么作用
-
虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下: -
对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到到页面。 -
用index作为key可能会引发的问题:
若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。 -
开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示, 使用index作为key是没有问题的。
10、列表使用indexOf('')=0
不等于-1
11、操作数据
方法 | 是否改变源数据 | 传入数据 | 返回代码 | 返回值 |
---|---|---|---|---|
filter | 否 | 过滤条件 | 返回过滤后的数据 | |
sort | 否 | 比较的两个值(a,b) | b-a:升序 a-b:降序 | 返回排序后的数据 |
12、vue是如何监听对象数据变化的
观察者,创建一个Observer,监视的实例对象,用于监视实例的对象
-
汇总对象中所有的属性形成一个数组
-
遍历
//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
console.log(obs)
//准备一个vm实例对象
let vm = {}
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}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
obj[k] = val
}
})
})
}
13、Vue.set()
原始创建的对象添加一个属性时,vm._data中没有get和set方法,在vm身上也没有此属性,因为vm是代理的data中的数据,vm和vm._data不允许作为对象目标
如果想要给对象添加属性且赋值时,使用
Vue.set(vm._data.对象名称,属性名,属性值)
vm.$set
和Vue.set的实现一致
14、vue监听数组变化
vue将侦听数组的变更方法(7个)进行包裹,所以会触发视图更新,或者使用set方法
比如更换第一个,可以使用splice(0,1,新的值),或者是使用
set(数组,0,新的值)`
直接取到数组的索引去修改值是不会触发视图的变化的,但是数组对象可以
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. s e t ( ) 特别注意: ‘ V u e . s e t ( ) ‘ 和 ‘ v m . set() 特别注意:`Vue.set() `和 `vm. set()特别注意:‘Vue.set()‘和‘vm.set()` 不能给vm 或 vm的根数据对象 添加属性!!!
15、vue收集表单数据
v-model双向数据绑定,默认收集的数据为value的值,但是单选和多选一般没有value,所以要给他设置一个value值,v-model绑定初始值能够影响v-model收集回来的数据,所以多选框选中初始值设置为一个空数组
收集表单数据:
若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
若:<input type="checkbox"/>
1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的的就是value组成的数组
v-model的修饰符:
-
v-model.number
收集数据为一个数据类型,一般和type='number
一起使用 -
输入框是实时收集,如果加上
v-model.lazy
,则在失去焦点的一瞬间去收集 -
v-model.trim
去掉前后的空格
16、过滤器
日期处理:
-
momentjs
-
dayjs
使用管道符,可以传参,第一个一直是数据本身
17、指令
内置指令
v-bind : 单向绑定解析表达式, 可简写为 :xxx
v-model : 双向数据绑定
v-for : 遍历数组/对象/字符串
v-on : 绑定事件监听, 可简写为@
v-if : 条件渲染(动态控制节点是否存存在)
v-else : 条件渲染(动态控制节点是否存存在)
v-show : 条件渲染 (动态控制节点是否展示)
v-text :
1.作用:向其所在的节点中渲染文本内容。
2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
v-html:
1.作用:向指定节点中渲染包含html结构的内容。
2.与插值语法的区别:
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html可以识别html结构。
3.严重注意:v-html有安全性问题!!!!
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
v-cloak:
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
v-once指令:
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
v-pre指令:
1.跳过其所在节点的编译过程。
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
自定义指令
<!--
需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
自定义指令总结:
一、定义语法:
(1).局部指令:
new Vue({ new Vue({
directives:{指令名:配置对象} 或 directives{指令名:回调函数}
}) })
(2).全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
二、配置对象中常用的3个回调:
(1).bind:指令与元素成功绑定时调用。
(2).inserted:指令所在元素被插入页面时调用。
(3).update:指令所在模板结构被重新解析时调用。
三、备注:
1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
-->
<!-- 准备好一个容器-->
<div id="root">
<h2>{{name}}</h2>
<h2>当前的n值是:<span v-text="n"></span> </h2>
<!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
<h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
<button @click="n++">点我n+1</button>
<hr/>
<input type="text" v-fbind:value="n">
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
//定义全局指令
/* Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
}) */
new Vue({
el:'#root',
data:{
name:'尚硅谷',
n:1
},
directives:{
//big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
/* 'big-number'(element,binding){
// console.log('big')
element.innerText = binding.value * 10
}, */
big(element,binding){
console.log('big',this) //注意此处的this是window
// console.log('big')
element.innerText = binding.value * 10
},
fbind:{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
}
}
})
生命周期
-
初始化:生命周期、事件,但数据代理还未开始
-
beforeCreated:此时无法通过vm访问到data中的数据和methods中的方法
-
初始化:数据监测、数据代理
-
created:可以通过vm访问到data中的数据和methods中的方法
-
vue开始解析模板,生成虚拟dom(内存中),页面害不能显示解析好的内容
-
befrewMount:页面呈现的是未经vue编译的dom结构,所有对dom的操做,最终都不生效
-
将内存中的虚拟dom转为真实dom插入页面
-
mounted:
-
-
页面中呈现的是经过vue编译的dom
-
对dom的操做均有效(尽可能避免),初始化过程结束。一般再次进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操做
-
-
beforeUpdate: 此时data中的数据已经更新,但页面是旧的
-
生成新的虚拟dom,与旧的进行比较,最终完成页面的更新
-
updated:数据是新的,页面也是新的,页面和数据保持同步
-
beforeDestroy: 对数据的修改不会再触发视图的更新,清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
-
destroryed:(react中没有此钩子)完全销毁一个实例,清理他与其他实例的链接,解绑它的全部指令及自定义事件监听器
组件
组件初始
vue.extend
:vue创建组件
组件定义时不能写el
,因为组件最后服务于一个vm
data为什么是函数:因为如果data是对象,a和b中的data都有c,修改data中的c时,a和b的c的都会改变,vm的组件可以是对象,但是组件的必须是函数
- 创建组件
Vue.extend({
data:{
return {}
},
template:`<div>school组件</div>`//组件
})
-
注册组件(局部注册)
new Vue({ el:'#root', compontents:{ school:school } })
-
使用 编写组件标签
<template> <div> <school></school> </div> </template>
注册全局组件
Vue.components('school',school)
VueComponents
-
组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
-
我们只需要写
<school/>
或<school></school>
,Vue解析时会帮我们创建school组件的实例对象, 即Vue帮我们执行的:new VueComponent(options)
。 -
特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponen
-
(1).组件配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
(2).new Vue(options)配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
-
VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。
一个重要的内置关系
函数身上有显示原型,实例对象身上有隐式原型,指向同一个
实例的隐式原型永远指向自己缔造者的原型对象
VueComponent.prototype.__proto__ = Vue.prototype
由于VueConponent
的原型对象也是一个普通的object
对象,所以他的隐式原型指向object
的原型对象,但是vue
将VueComponent
的隐式原型指向了vue
的原性对象
原因:数据沿着隐式原型链去查找数据,可以让组件的实例对象(vc)也可以访问到vue原型上面的属性、方法
单文件组件
App.vue管理所有的组件,注册在main.js里面,index.html主页面中放div