文章目录
Vue简介
Vue的特点
3、使用虚拟DOM+优秀的Diff算法,尽量复用DOM节点。
Hello, Vue
1、Vue实例与HTML容器是一一对应的,使用el属性让容器与Vue实例关联起来。
2、Vue可以使用插值语法(双层花括号)解析Vue的data属性,插值语法还可以解析其他的js表达式(所谓js表达式,就是可以产生一个值的js语句,一般为元素赋值语句的等号右边部分或者函数的返回值)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="../js/vue.js"></script>
<title>初始Vue</title>
</head>
<body>
<script type="text/javascript">
Vue.config.productionTip = false; // 开发环境, 关闭vue对于生产环境的提示信息
</script>
<div id = "r1">
<h1>
{{msg}} // vue的插值语法
</h1>
</div>
<script type="text/javascript">
const x = new Vue({
el: "#r1", // el element 元素 表示当前vue实例要控制的区域 类似css的条件选择器
data: {
msg: "hello vue"
}
});
</script>
</body>
</html>
Vue基本语法
模板语法
Vue模板语法有2大类:
1、插值语法:
- 功能:用于解析标签体(开闭标签之间部分)内容。
- 写法:{{****}} ****是js表达式,且可以读取vue实例中data的所有属性。
2、指令语法:
- 功能:用于解析标签(包括标签属性,标签体内容,绑定事件……)
- 举例:
v-bind:href = "***"
或简写为 ::href="***"
,***同样要写js表达式,且可以直接读取到data中的属性。 - 注:vue中除了
v-bind
还有很多v-???
的属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="../js/vue.js"></script>
<title>初始Vue</title>
</head>
<body>
<script type="text/javascript">
Vue.config.productionTip = false; // 开发环境, 关闭vue对于生产环境的提示信息
</script>
<div id = "root">
<h1>
差值语法
<h3>{{name}}</h3> // vue的插值语法
</h1>
<h1>
指令语法
<a v-bind:href="school.url.toUpperCase()">点我去{{school.url}}学习</a>
</h1>
</div>
<script type="text/javascript">
const x = new Vue({
el: "#root", // el element 元素 表示当前vue实例要控制的区域 类似css的条件选择器
data: {
name: 'jack'
school:{
name:'ULCA',
url:'https://www.ulca.com'
}
}
});
</script>
</body>
</html>
数据绑定(v-bind、v-model)
Vue中有2中数据绑定方式:
- 1、单向绑定(v-bind):数据只能从data流向页面
- 2、双向绑定(v-model):数据不仅能从data流向页面,也可以从页面流向data。
- 双向绑定一般应用在表单元素上(如:input、select等,这些元素都有value属性,v-model绑定的正是这个value属性)
- v-model:value 可以简写为v-model,因为v-model默认收集的就是value值。
el与data的两种写法
el:
- 使用el属性绑定容器
- 使用代码
.$mount('#root')
绑定
下边演示了一个案例,使用一个定时器,在1秒后再建立vue实例与html容器之间的关联。
data:
- 使用data属性,对象式
- 使用函数返回值,函数式。当学习组件时,data必须使用函数式,否则会报错。
- 一个重要的原则,由Vue管理的函数,不可以写箭头式,一旦写了箭头式,this就不再是Vue实例了。
事件处理(v-on:click / @click)
- 使用
v-on:×××
或@×××
绑定事件,其中×××
是事件名。 - 事件的回调需要配置在
method
对象中,最终会在vm上。 - method中配置的函数都是被Vue管理的函数,this指向的就是组件实例对象,最好不要用箭头函数(lambda)表示。
@click="demo" 和 @click="deme($event)"
效果是一致的,但是后者可以给函数传参数。
事件修饰符
Vue中的事件修饰符:
- prevent:阻止默认事件(常用)
- stop:阻止事件冒泡(即事件不会向外层传播,常用)
- once:事件只触发一次(常用)
- capture:使用事件的捕获模式(即外层容器的事件也会被捕获)
- self:只有event.target是当前操作的元素才触发事件
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕。
键盘事件(缺)
计算属性与监视(computed、watch)
计算属性-computed
计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
计算在虚拟dom中进行,计算结果在缓存中,不会随时间变化,当计算属性中的参数有更新时,虚拟dom清空,重新计算,这时计算属性才会发生变化。
注意计算属性是vue component的属性,可以用方法定义,但不可用作方法调用。
计算属性的优势:有缓存,多次调用,只计算一次。仅当计算所依赖的数据变化后才会重新修改。
computed: {
fullname:{
get(){
return this.firstName + '-' + this.lastName;
}
}
}
计算属性:也可以使用函数返回值设置,但是methods,computed 方法名不能重名,重名字后,只会调用methods的方法。
computed: {
//计算属性:methods,computed 方法名不能重名,重名字后,只会调用methods的方法
fullname: function () {
return this.firstName + '-' + this.lastName;
}
// 或者函数也可直接这样写:
fullname() {
return this.firstName + '-' + this.lastName;
}
}
监视属性-watch
监视属性有两种配置方式:
- Vue实例中使用
watch
- 调用Vue实例的
.$watch
方法
主要是可以设置handler(new, old)方法,每次监测的值变化时,都会调用该方法。
和计算属性一样,监测属性也可以进行简写:
深度监视-deep
监视多级结构中的某个属性时,使用’number.a’指定对象的key。
深度监视:
- Vue中的watch默认不监测对象内部值的改变
- 配置deep:true,则可以监测对象内部值的改变(多层)
在下边的例子中number对象开启了深度监测,无论属性a还是b变化,都会触发handler()。
computed和watch的区别
- computed能完成的功能,watch都可以完成。
- watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
两个重要的小原则:
- 被Vue管理的函数,最好不要写为箭头函数,即写成普通函数,这样this的指向才是Vue实例对象。
- 所有不被Vue管理的函数(定时器回调函数,Ajax的回调函数等),最好写成箭头函数,这样this的指向才是Vue实例对象。
过滤器 - filters
过滤器可以对要显式进行特定格式化后再显示(适用于一些简单的处理逻辑),它使用管道处理的语法。
使用过滤器的语法:
{{xxx | 过滤器名}}
或者
v-bind:属性 = "xxx : 过滤器名"
过滤器filters
实际上也可以使用计算属性computed
或者方法methods
来实现,但过滤器filters
更加强调一种简单的函数处理逻辑,有点类似于C++中的inline函数
局部过滤器
局部过滤器针对某个特定的Vue实例有效。
过滤器也可以接受额外的参数,但是默认第一个参数是管道传来的前一项数据结果。
全局过滤器
全局过滤器针对所有的Vue实例都有效。
样式渲染
绑定class样式,:class
可以使用v-bind
或者简写为:
绑定class样式。
下面列举三种Vue绑定class样式的案例:
- 字符串写法,适用于样式类名不确定,需要动态绑定
- 数组写法,适用于要绑定的样式个数不确定,名字也不确定
- 对象写法,适用于要绑定的样式个数确定、名字也确定,但是需要动态决定是否使用。
字符串写法:
basic、normal、happy都是css类样式
数组写法:
样式数组classArr可以动态添加新的样式类型。
对象写法:
对象key就是样式类名,value决定是否使用该样式。
绑定style样式,:style
- :style = “{fontSize: +++}”,其中+++是动态值
- :style = “[a,b]”,其中a、b是样式对象
条件渲染,v-if 与 v-show
- v-if:适用于切换频率较低的场景,不满足if条件的DOM元素直接被移除。
- v-if = “表达式”
- v-else-if = “表达式”
- v-else = “表达式”
- v-show:适用于切换频率较高的场景,不满足show条件的元素只是样式被隐藏。使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到。
列表渲染,v-for
v-for指令用于展示列表数据。
- 语法是
v-for = "(item, index) in xxx" : key = "yyy"
- 可以遍历数组、对象、字符串、指定次数
v-for中的key的作用与原理(缺)
列表过滤与排序(案例)
过滤功能实现效果案例:
输入人员名字,过滤出相关信息:
watch监测实现过滤
- 输入框使用v-model双向绑定输入的keyword
- 使用persons数组代表原数据,filterPersons表示过滤后的数据,使用条件渲染v-for,渲染过滤后的数据。
- 使用watch监测keyword,当值变化时,根据新值,过滤出新的数组。
- 注意indexof()函数,当不匹配时,返回-1,当匹配空字符串时,返回0,其余的返回关键字第一次出现的数组下标
- 由于filterPersons初始为空数组,为了显示原有的数据,应该使用
watch
的immediate
属性,让watch立即执行一次,那么此时关键字为空字符串,filterPersons过滤结果就是原始persons
<div id = "r1">
<h2> 人员列表
<input type="text" v-model="keyword" placeholder="请输入名字">
<ul>
<li v-for = "(p, index) of filterPersons" :key = "index">
{{p.name}} -- {{p.age}} -- {{p.sex}} -- {{p.id}}
</li>
</ul>
</h2>
</div>
<script type="text/javascript">
const x = new Vue({
el: "#r1", // el element 元素 表示当前vue实例要控制的区域 类似css的条件选择器
data: {
keyword: "",
persons: [
{id : '001', name: '马冬梅', age : '19', sex : '女'},
{id : '002', name: '周冬雨', age : '20', sex : '女'},
{id : '003', name: '周杰伦', age : '21', sex : '男'},
{id : '004', name: '扁嘴伦', age : '22', sex : '男'},
],
filterPersons: []
},
methods:{
},
watch: {
keyword: {
// 初始化时,立即执行一次,这样keyword的值就为空了,所以不会执行过滤,显示原始的persons内容
immediate: true,
handler(val) {
this.filterPersons = this.persons.filter(p => p.name.indexOf(val) != -1);
}
}
},
computed实现过滤
使用computed实现则更为简洁,只需要计算filterPersons数组,而filterPersons的计算依赖于keyword,因此每当keyword变化,自动重新计算filterPersons并渲染。
<div id = "r1">
<h2> 人员列表
<input type="text" v-model="keyword" placeholder="请输入名字">
<ul>
<li v-for = "(p, index) of filterPersons" :key = "index">
{{p.name}} -- {{p.age}} -- {{p.sex}} -- {{p.id}}
</li>
</ul>
</h2>
</div>
<script type="text/javascript">
const x = new Vue({
el: "#r1", // el element 元素 表示当前vue实例要控制的区域 类似css的条件选择器
data: {
keyword: "",
persons: [
{id : '001', name: '马冬梅', age : '19', sex : '女'},
{id : '002', name: '周冬雨', age : '20', sex : '女'},
{id : '003', name: '周杰伦', age : '21', sex : '男'},
{id : '004', name: '扁嘴伦', age : '22', sex : '男'},
],
// filterPersons: []
},
methods:{
},
// watch: {
// keyword: {
// // 初始化时,立即执行一次,这样keyword的值就为空了,所以不会执行过滤,显示原始的persons内容
// immediate: true,
// handler(val) {
// this.filterPersons = this.persons.filter(p => p.name.indexOf(val) != -1);
// }
// }
// },
computed:{
filterPersons(){
return this.persons.filter(p => p.name.indexOf(this.keyword) != -1);
}
}
});
</script>
添加排序功能
对过滤结果再添加排序功能:
- 添加一个字段sortType,用于记录当前排序的类型
在计算filterPersons数组中,根据sortType,排序:
computed:{
filterPersons(){
const arr = this.persons.filter(p => p.name.indexOf(this.keyword) != -1)
if (this.sortType) {
arr.sort((p1, p2) => this.sortType === 1 ? p1.age - p2.age : p2.age - p1.age)
}
return arr
}
}
其他v-?内置指令
v-text
作用是向所在的标签节点中渲染文本内容,它有两个特点:
- v-text:会替换掉标签节点中的所有内容,尽管标签中可能写有其他内容,它不会向插值语法
{{}}
那样自然拼接,而是完全替换。 - v-text:绑定的字符串数据内容,会被完完全全当做普通字符串处理,尽管绑定的字符串中有类似标签的字符。例如
<h>
v-html
v-html
与v-text
的唯一区别就在于,v-html
会将绑定内容中的标签结构解析出来,而v-text
则会完全当做普通字符处理。
v-html有安全性问题!!!!
(1)在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2)一定要在可信的内容上使用v-HTML,永远不要在用户提交的内容尚!!!
xss cookie攻击案例
有时候,我们登录了一个网站,浏览器会将服务器信息,存入cookie,cookie存在硬盘中,当关闭浏览器再次打开,由于cookie的存在,无需再次登录,就可进入个人账户。
由于cookie可以免登录,为了安全起见,cookie是不可跨浏览器使用的,即各个浏览器存入的cookie不可共享。
那么假如,我们把一个浏览器存入某个网站的cookie全部记录下来,在另一个浏览器打开相同的网站,存入cookie,就有可能通过盗取cookie在另一台电脑上实现cookie免登录!!!
在chrome浏览器,使用 cookie editor
导出GitHub网站的所有cookie。
在火狐浏览器中,使用 cookie editor
,将刚刚导出的cookie,导入。
刷新浏览器,实现了登录。
携带cookie跳转网站,可能泄露个人信息。
v-cloak
cloak:斗篷,这个属性字段不需要绑定值,在HTML加载时有这个cloak属性,当渲染完毕时,这个属性就消失了,就像给标签加了一个斗篷,渲染完毕后,将斗篷扯开。
使用css配合 v-cloak可以解决网速慢时,页面出现{{xxx}}的问题
下边代码中,
script 的src导入需要5s,html显示很快,但是渲染需要等待script 的src导入。
加入cloak,再使用css在style中,匹配有v-cloak
属性的标签,不展示。则等待时就不会出现{{xxx}}。
v-once
v-once所在标签节点在初次动态渲染后,就会被视为静态内容,以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
v-pre
v-pre指令跳过所在节点的编译过程,可以利用它跳过,没有使用指令语法,没有使用差值语法的节点,起到加快编译的作用。
实际上就是对静态内容进行表示,提前预编译
Vue自定义指令(缺)
函数式
对象式
Vue数据代理与数据监测
数据代理实现原理
Object.defineProperty()
Object.defineProperty()字面意思就是可以为对象设置属性,且在设置属性时,可以控制属性的一些高级选项:
- enumerable:是否可以枚举
- writable:是否可修改
- configurable:是否可删除
此外可以设置属性的get()和set()方法。
数据代理
- Vue中通过VM实例对象来代理data对象属性中的操作(读/写)
- 数据代理可以更加方便的操作data中的数据
- 实现原理:通过Object.defineProperty()把data对象中所有属性添加到vm上,为每一个属性指定getter和setter方法,在这些方法中去读/写data中对于的属性。
数据监测
由数据代理可知,vue实例中data的属性字段,其实都是来自于_data,_data中的数据,才是我们在创建vue实例时,在data:中写入的内容,即 对于一个vue实例vm,vm._data === data
vue框架使用数据代理主要做了两件事:
- 1、将我们的data中的每一组 k-v,添加响应式的getter()和setter()方法。
- 2、使用vm_data = data,完成赋值。
响应式的getter()和setter()方法,完成了对vue实例对象每一个数据属性的监测,当需要读数据时,自动调用getter()方法,读取_data中对应的数据,当需要写数据时,自动调用setter()方法,将修改写回_data。
监测对象 - Vue.set() / vm.$set()
倘若在创建vue实例时,对于data的某个对象属性不确定,要在后边动态的给data中某个对象动态添加一个属性。
一般有两种方式:
1、使用Vue.set(src, k, v)方法
其中src是data中的某个数据对象,k是对象键,v是值。
2、使用vm.$set(vm.ele, k, v)方法
其中vm.ele是vue实例data中某个数据对象,k是对象键,v是值。
注意
1、只有通过上述两种方法添加的属性,Vue框架才会给属性添加setter()和getter()方法,该属性的读写才可以被Vue框架所监测到
2、上述第一种方法,src不可以直接填vm实例本身,不可以直接给data新增一个属性,只能是对已有的data的某个属性,添加新的属性k-v
举例:
假如原来data中有student这个对象属性,它有name和age两个属性字段,后续想通过按钮给他添加一个属性性别。
<div id = "r1">
<h2> 人员属性 </h2>
<button @click = "addSex1">添加性别男</button>
<button @click = "addSex2">添加性别女</button>
<h3>
姓名:{{student.name}}
</h3>
<h3>
年龄:{{student.age}}
</h3>
<h3 v-if = "student.sex">
性别:{{student.sex}}
</h3>
</div>
<script type="text/javascript">
const x = new Vue({
el: "#r1", // el element 元素 表示当前vue实例要控制的区域 类似css的条件选择器
data: {
student:{
name: 'lzy',
age: 24
}
},
methods: {
addSex1() {
// 1. Vue.set()
Vue.set(this.student, 'sex', '男')
},
addSex2() {
// 2. .$set()
this.$set(this.student, 'sex', '女')
},
}
});
</script>
监测数组 - 包裹
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
所谓包裹就是说,Vue对数组的上述方法进行进一步封装,使其在实现上述数组功能的同时,能被监测触发更新。
注:上述方法的特征是调用后会改变原始数组。相比之下,也有非变更方法,例如 filter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
Vue生命周期
- 1、beforeCreate():数据代理尚未开始,此时无法通过vm访问到data中的数据,methods中的方法。
- 2、created():数据监测和数据代理完成了,可以通过vm访问到data中的数据,methods中的方法。
- 3、beforeMount():页面呈现的是未经Vue编译的DOM结构,所有对DOM的操作,最终都不奏效。
- 4、mounted():页面中呈现的是经过Vue编译的DOM,此时对DOM的操作均有效,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作。
1-4步骤构成了挂载的主要流程
- 5、beforeUpdate():此时数据是新的,但是页面是旧的,即新的数据尚未更新到页面上。
- 6、updated():此时,页面的显示的是新数据,页面和数据同步完毕。
- 7、beforeDestroy():此时vm中所有的data、methods、指令等等,都处于可用状态,马上要执行销毁的过程,一般在此阶段:关闭定时器、取消订阅消息,解绑自定义事件等收尾操作。
- 8、destroyed():销毁完毕。可以使用
this.$destroy()
,让vue实例自己销毁,Vue实例销毁后,自定义事件会失效,但原生DOM事件依然有效。