前端从后端获取到数据之后,如何将其展示到页面上?
原生DOM操作,将数据一个个的往上放
字符串拼接法
模板引擎
数据驱动的MVVM框架
Vue等这些框架做的事情,其实就是简化数据渲染的操作!提高开发效率的!!
框架(Framework)
框架是一整套完整的解决方案,我们需要将自己的代码按照框架的规则,放在合适的位置,框架会在合适的时机,帮我们调用代码,实现指定的功能。(framework call you)
类库(Library)
类库是一系列方法的集合,在我们编程的时候,我们需要自己决定什么时候,调用哪个方法,实现什么功能。(you call library)
MV*模式指的其实就是对代码进行按照功能划分模块的方式!
Model: 和数据相关的代码,负责提供数据的!
View: 和展示相关的代码,负责展示数据的!
Controller: 负责将数据转交给视图,同样负责从视图中收集数据,转交给Model(需要程序员自己控制)
Model、View:与MVC的是一样的
View-Model: 这个部分是由框架实现的,不需要程序员再进行开发了,就可以自动实现数据到视图,以及视图到数据的流程!
渐进式的JavaScript框架
渐进式(Progressive)
Vue的核心功能非常小,可以用来支撑小型的网页的开发,Vue还支持其他额外的一些插件,可以逐步的扩展框架的功能用以支撑大型企业级项目的开发。 由小到大演变的过程,其实就是所谓的渐进式。
安装vue 通过npm 或者yarn(也可以直接去官网下载vue.js文件)
在页面中引入vue.js文件
在script标签中创建Vue的实例
const vm = new Vue({
// 当前vue实例要控制的元素范围,放元素的id
el:'#app',
data:{
// data中放的就是要在视图中展示的数据
name:'zs'
}
})
// 如果之前用过模板引擎的,比如art-template,这里就可以类比的来看
// art-template中使用的方式 template('模板id',对象类型的数据)
`el: '#app'` // 相当于和页面建立了绑定关联
`data:{...}` // 相当于说绑定的那部分数据是什么
在HTML代码中创建视图对应的元素
在视图元素的范围内,通过插值表达式或者指令来使用Vue的功能
<div id='app'>
<h1>
{{name}}
h1>
div>
什么是数据驱动? 就是通过控制数据的变化来改变某物或某事。
Vue的数据驱动中, 数据驱动什么? 就是说物或者事是什么? 这里的vue数据驱动的是视图也就是DOM元素让DOM的内容随着数据的改变而改变, 这里视图(DOM)可以理解成上面的改变的某物或者某事
如果想要操作页面元素的变化,不要再去想DOM操作了!!要想办法通过修改数据来达成效果!
可以看到我们上面使用{{name}}这样的方式把数据绑定到了页面上,这种语法我们叫做插值表达式
也叫做小胡子语法
表达式和语句怎么区分? (参考说明 https://zhuanlan.zhihu.com/p/38622128)
语句是为了进行某种操作,一般情况下不需要返回值,而表达式都是为了得到返回值,一定会返回一个值(这里的值不包括undefined)。
简单的理解就是:表达式指的就是有值得内容, 我们把他放到等号的右边,看能不能成立,如果可以,就是表达式
插值表达式中可以出现的内容
插值这里存在一个问题——插值闪烁
原因:Vue加载太慢,没人处理插值表达式,直接原样显示在页面上,等Vue加载完了,才会处理,这时数据才会展示出来,会有闪烁的效果出现
解决方案: v-cloak
给元素添加v-cloak指令
<h1 v-cloak>{{name}}h1>
在style标签中添加一个 v-cloak的属性选择器样式 display:none
[v-cloak]{
display:none
}
解决的原理: 一开始先隐藏,当Vue加载完了,数据渲染完成,就把v-cloak删掉,数据就显示出来了!
数据绑定,说的就是,将数据和视图关联起来
<input type="text" :value="name">
双向绑定:当数据发生变化的时候,页面中的内容会随之变化,页面中的内容发生变化的时候,数据也会随之变化 双向绑定一般只会出现在表单元素中!
<input type="text" v-model="name">
双向绑定原理
可以分为两部分,一部分是视图数据变化,如何去改变绑定的数据,另一部分是绑定的数据改变,如何去改变视图数据。
第一部分是很简单的,我们可以监听表单控件的input事件,就可以知道数据发生了修改,但是关键是第二部分,我们怎么知道绑定的数据修改了呢?
Object.defineProperty方法
// 1. 如何给对象添加一个属性?
let obj = {name: ""}
obj.age = 18;
obj["gender"] = "male";
// Object.defineProperty可以用来给对象添加属性,也可以用来修改现有的属性
// 在添加属性的时候,可以设置属性以下的特性:
// 1. 是否为只读属性
// 2. 是否可以删除
// 3. 是否可以遍历
// 4. 可以为属性注册像改变事件一样的函数
// Object.defineProperty(要添加或者修改属性的对象, 要添加或者修改的属性名, 特征对象)
Object.defineProperty(obj, "name", {
// 1. 默认的,该属性是只读的,不能被赋值 默认是false
writable: true,
// 2. 默认的,该属性不能被for in循环遍历 默认是false
enumerable: true,
// 3. 默认的,该属性不能被delete删除 默认是false
configurable: true,
// value属性用来设置属性的默认值
value: "123"
})
let nameValue = "";
Object.defineProperty(obj, "name", {
// set和get不能和上面的额writable,value同时出现
set(value){
// 这个函数就像是属性的改变事件,我们在给属性赋值的时候
// JS内部会自动调用这个函数
console.log("属性被赋值了");
// 在set函数中,需要接收用户所赋值的内容,也就是等号右边的内容 可以通过value形参接收
// 将其存储起来
nameValue = value;
},
get(){
// 这个函数就像是属性的被获取的事件,只要有人用到这个属性了,那这个函数就会被调用
console.log("属性被获取值了")
// 这个函数会在用户获取值得时候调用,用户获取到的值,就是当前函数的返回值
return nameValue;
}
})
通过Object.defineProperty 方法我们就可以像监听事件一样来监听绑定数据是何时修改的,然后把这个修改后的数据重新帮到表单控件上
let nameValue = "";
Object.defineProperty(obj, "name", {
set(value){
input.value = nameValue = value;
},
get(){
return nameValue;
}
})
如果页面中需要某个数据,而这个数据是根据当前data中的数据计算出来的,那么我们就使用计算属性。计算属性的本质: 就是一个函数,这个函数会有一个返回值
计算属性的使用
<div id="app">
FirstName<input type="text" v-model="firstName">
LastName<input type="text" v-model="lastName">
FullName<input type="text" v-model="fullName">
div>
<script>
const vm = new Vue({
el: "#app",
data: {
firstName: "",
lastName: ""
},
computed: {
// 计算属性的属性名
fullName(){
return this.firstName + "·" + this.lastName
}
}
})
</script>
//因为我们用v-model进行了双向绑定,所以我们就需要使用完整形式来类似于监听数据的修改(用set监听)
fullName: {
get(){
// 这个函数会在用户获取这个计算属性值得时候调用,返回值就是用户获取到的值
return this.firstName + "·" + this.lastName
},
set(value){
// 这个函数会在用户为这个计算属性赋值的时候调用
// 在这个函数中,我们可以对fullname进行拆分
// value就是用户给这个计算属性赋的值
this.firstName = value.split("·")[0]
this.lastName = value.split("·")[1]
}
}
}
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过
watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
侦听器的使用
const vm = new Vue({
el: "#app",
data: {
msg: "hello world"
},
watch: {
// watch属性是一个对象,对象中的属性名就是要监视的数据(data中的)的名字
// 当这个数据发生变化的时候,这个函数会自动被执行
// 并且Vue提供了两个参数,newValue 是修改后的值, oldValue 是修改前的值
msg(newValue, oldValue){
console.log("msg发生变化了", newValue, oldValue)
}
}
})
侦听器完整形式
const vm = new Vue({
el: "#app",
data: {
person: {
name: "张学友",
age: 18
}
},
watch: {
// 如果要监视对象中的属性的变化,不能只写对象的名字
// 因为对象是个引用类型的数据,属性发生变化的时候,地址是不会变化的
// 地址不变化,监视就不生效
// 我们需要在监视属性的时候,将对象.属性名作为监视函数的名字,这样就能监视到属性的变化了
// 这么写是非常麻烦的,特别是针对属性特别多的时候,对于简单类型数据来说可以这么写
"person.name": function(newValue, oldValue){
console.log("person.name发生变化了", newValue, oldValue)
},
"person.age": function(newValue, oldValue){
console.log("person.age发生变化了", newValue, oldValue)
}
// watch的平时的写法只是一个简写形式,他还有一个完整形态
// 针对数组、对象这样的复杂类型需要如下这么写
person: {
handler(newValue, oldValue){
console.log("person变化了")
console.log(newValue, oldValue)
},
// 进行深度监视,只要对象的任意属性发生变化,都会触发这个监视函数
// 进行深度监视的时候,newValue和oldValue值一样,因为监视的是引用类型的值,newValue和oldValue指向的是同一个对象
deep: true,
// 这个属性设置的是,代码一开始运行,就执行一次handler函数!
immediate: true
}
}
})
过滤器其实就是一个函数,允许你自定义过滤器,可被用于一些常见的文本格式化,过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
{{ message | capitalize }}
<div v-bind:id="rawId | formatId">div>
{{ message | capitalize(arg1,arg2)}}
注:过滤器可以串联
{{ message | filterA | filterB }}
定义全局过滤器
全局注册的过滤器,当前页面中所有的vue实例都可以使用
Vue.filter('过滤器名', function('要过滤的数据',arg1,arg2){
// 对过滤的数据进行加工后输出
return xxx
})
定义局部过滤器
只在某个vue实例中生效(是私有的) 在创建vue实例的时候,参数对象中添加一个 filters属性,将过滤器函数注册在这个对象中即可
{{message | dateFormat('YYYY-MM-DD')}}
const vm = new Vue({
el:'#app',
data:{
message:new Date() // Tue Jun 18 2019 20:20:33 GMT+0800 (中国标准时间)
},
filters:{
// 第一个参数就是原始的日期,第二个参数是传递的需要的日期格式
dateFormat(data,pattern){
// 这里使用了moment.js这个库
return moment(data).format(pattern)
}
}
})
有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令(自定义指令在实际开发中用的不多)
以Vue官网的Demo为例
<div id='app'>
<input type='text' v-focus>
div>
可能会有疑问直接用autofocus这个不就能自动获取焦点了吗?但是这里是有问题的,当我们加了autofocus 这个属性后,界面一开始的确执行了这个属性,但是因为上面这部分代码是在Vue控制的区域中的,Vue自身生命周期会对这段代码进行编译,导致之前执行一次的autofocus不会再一次执行,因此不会起作用,因此需要用到自定义指令
全局自定义指令
// 注意:这里的指令名是不带 v- 的,但是界面上使用的时候需要带 v-
Vue.directive('focus',{
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
局部自定义指令
const vm = new Vue({
el:'#app',
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
})
指令钩子函数
什么是钩子函数?钩子函数指的就是在特定的时机下触发的函数
Vue.directive('focus',{
bind(el,binding){ // 比较常用
// 在vue开始解析这个指令的时候执行的
// 在这里一般可以进行一些样式的设置,比如设置字体颜色、字体粗细等
},
inserted(el,binding){
// 在vue将当前指令所在的元素渲染到页面上的时候执行的
// 比如执行自动获取焦点的操作,需要在inserted中执行
},
update(el,binding){ // 比较常用
// 当当前指令绑定的数据发生变化的时候,页面元素还没有更新的时候调用
// 一般update中执行的和bind中执行的差不多,以此就有了后面的简写形式
},
componentUpdated(el,binding){
// 当当前指令绑定的数据发生变化的时候,页面元素更新全部完成时候调用
},
unbind(el,binding){
// 指令被卸载的时候调用
}
})
钩子函数参数说明
{ foo: true, bar: true }
指令的简写形式
在很多时候,你可能想在
bind
和update
时触发相同行为,而不关心其它的钩子。比如这样写:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello world!'
},
directives: {
mytext(el, binding) {
el.innerText = binding.value
}
}
})
一个实例从开始到最后消亡所经历的各种状态,就是一个实例的生命周期
总体可以分为三个阶段:初始化阶段、更新(运行)阶段、销毁(卸载)阶段
初始化阶段
这个时候,我们就在页面上看到了有数据的html元素了!!!
更新(运行)阶段
销毁(卸载)阶段
create: 在数据初始化前后调用的事件
mount: 在将有数据的元素挂载到页面前后调用的事件
update: 数据发生改变,页面更新前后调用的事件
destroy: 当vm.$destroy被调用,资源释放前后调用的事件
const vm = new Vue({
el:'#app',
data:{
msg:'hello world'
},
beforeCreate() {
// beforeCreate 数据初始化之前执行的,这时候还没数据
// console.log(this.msg);
console.warn("beforeCreate 被执行了")
},
created() {
// 能够访问数据最早的钩子函数,其实就是created
// 重点: 工作中最常用的就是这个钩子函数
// 页面一家在就要请求数据的ajax请求一般都在这里发送
// console.log(this.msg);
console.warn("created 被执行了")
},
beforeMount() {
// console.log(document.getElementById("app"));
console.warn("beforeMount 被执行了")
},
mounted() {
// console.log(document.getElementById("app"));
// 如果在实际开发当中,我们要访问有数据的DOM,那么久需要在mounted钩子函数里去做
console.warn("mounted 被执行了")
},
beforeUpdate() {
// 这里可以访问更新前的DOM
console.log(document.getElementById("app").innerHTML);
console.warn("beforeUpdate 被执行了")
},
updated() {
// 这里可以访问更新后的DOM
console.log(document.getElementById("app").innerHTML);
console.warn("updated 被执行了")
},
beforeDestroy() {
console.warn("beforeDestroy 被执行了")
},
destroyed() {
console.warn("destroyed 被执行了")
}
})
根据需要添加相应的属性参数
const vm = new Vue({
el:'#app',
data:{
msg:'hello world!'
},
methods:{
// 定义函数、事件处理函数
fn(){}, // 简写方式
fn1:function(){}
},
computed:{
cmp(){return 数据},
cmp1:function(){return 数据},
// 完整形式,一般有双向绑定的时候会用到这完整形式
cmp:{
get(){
return 数据
},
set(value){
this.xxx = value
}
}
},
watch:{
msg(newValue, oldValue){
// msg数据改变的时候自动执行
},
// 完整形式
msg:{
handler(newValue, oldValue){
// msg数据改变的时候自动执行
},
deep:true, // 默认是false
immediate:true // 默认是false
}
},
filters:{
// 局部过滤器
// 参数一定死了是 管道符 "|" 前面的值
dateFormat(data,arg1,arg2){},
dateFormat:function(data,arg1,arg2){}
},
directives:{
// 局部自定义指令
mytext:{
// 指令钩子函数
bind(el,binding){},
inserted(el,binding){},
update(el,binding){},
componentUpdated(el,binding){},
unbind(el,binding){}
}
},
beforeCreate(){},
created(){},
beforeMount(){},
mount(){},
beforeUpdate(){},
updated(){},
beforeDestroy(){},
destroyed(){}
})
vue中内置了很多自定义的类似于html属性的东西(带有
v-
前缀的特殊特性),每个vue提供的这种属性都会对应一个特定的功能,这些类似于自定义属性的东西就叫做指令,职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
先定义一个Vue的实例,后面的指令都取值自这里
const vm = new Vue({
el:'#app',
data:{
msg:'hello world',
msg1:'hello world
'
imageSrc:'./logo.png',
size:24,
isShow:true,
classA:{
red:true,
bd:false
},
divStyle1: "width: 100px; height: 100px; background-color: pink;",
divStyle2: {width: "100px", height: "100px", backgroundColor: "pink"},
divStyle3: {width: "50px", height: "50px", backgroundColor: "green"},
items:['zs','ls','ww'],
items1: [
{id:1, name: 'zs', age: 18 },
{id:2, name: 'ls', age: 24 },
{id:3, name: 'ww', age: 30 }
]
}
})
在Vue中给标签的属性赋值数据的时候,不可以使用插值表达式,因此需要用到v-bind
<img v-bind:src="imageSrc">
<img :src="imageSrc">
<div id="box" :class="{red: true, db: true}">div>
<div id="box" :class="classA">div>
<div :class="[classA, { classB: true, classC: false }]">
<div :style="divStyle1">div>
<div :style="[divStyle2, divStyle3]">div>
<div :style="['red', 'db']">div>
基于源数据多次渲染元素或模板块,可以实现数组/对象/字符串/数字/Iterable的遍历
<div v-for="item in items">
{{ item }}
div>
<div v-for="(item, index) in items">{{item}} - {{index}}div>
<div v-for="(val, key) in object">div>
<div v-for="item in items" :key="item.id">
{{ item.text }}
div>
<div v-for='item in 5'>
{{item}}
div>
<div v-for='item in "hello"'>
{{item}}
div>
v-for使用最好如下,与key配合使用
当 Vue 正在更新使用 v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
“就地更新”:当在进行列表渲染的时候,vue会直接对已有的标签进行复用,不会整个的将所有的标签全部重新删除和创建
<div v-for="item in items" :key="item.id">
{{ item.text }}
div>
增加Key的好处
根据表达式之真假值,切换元素的
display
CSS 属性。
<div id="box" v-show="isShow">hello worlddiv>
根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建,即为false是删除标签和标签数据,为true时重新创建标签和绑定数据
<div id="box" v-if="isShow">hello worlddiv>
v-show 和 v-if 比较
区别
应用场景
这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如
[v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
<div v-cloak>
{{ message }}
div>
[v-cloak] {
display: none;
}
更新元素的 内容
<span v-text="msg">span>
<span>hello worldspan>
v-text指令和之前的插值表达式很像,但是两者有区别
更新元素的
innerHTML
<div v-html='msg1'>div>
<div>
<h1>
hello world
h1>
div>
绑定事件监听器,事件类型由参数指定
<button v-on:click="btnClickHandler">点我呀!button>
<div id="box" v-on:mouseenter="divMouseEnterHandler">div>
<button @click="btnClickHandler">点我呀!button>
<div id="box" @mouseenter="divMouseEnterHandler">div>
<button @click="btnClickHandler(100)">点我呀!button>
<input type="text" :value="name" @input="e => name = e.target.value">
调用的事件处理函数需要定义在Vue实例的methods中
const vm = new Vue({
el: "#app",
methods: {
btnClickHandler(arg){
// alert("点你咋地!!")
alert(arg);
},
divMouseEnterHandler(){
console.log("我进来了")
}
}
})
事件对象
如果在注册事件的时候,直接赋值的是函数的名字,不带小括号,那么vue会自动将事件对象传递给这个事件处理函数
<input type="text" @keyup="keyupHandler">
const vm = new Vue({
el: "#app",
methods: {
keyupHandler(e){
console.log(e)
}
}
})
如果在注册时间的时候,使用的是带有小括号的形式,则要获取事件对象,需要手动的传递参数$event
<input type="text" @keyup="keyupHandler($event)">
事件修饰符
<div class="parent" @click="parentClickHandler">
<div class="child" @click.stop="childClickHandler">div>
div>
常用的事件修饰符
.stop
- 调用 event.stopPropagation()
。
.prevent
- 调用 event.preventDefault()
。
.capture
- 添加事件侦听器时使用 capture 模式。
.self
- 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.once
- 只触发一次回调。
事件修饰符是可以连写的
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为
v-on
在监听键盘事件时添加按键修饰符
<input v-on:keyup.enter="submit">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
还可以通过全局 config.keyCodes
对象自定义按键修饰符别名
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
在表单控件或者组件上创建双向绑定,你可以用
v-model
指令在表单、
及
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}p>
<input type="checkbox" id="checkbox" v-model="checked">
注:在文本区域插值 (
) 并不会生效,应用
v-model
来代替。
v-model
在内部为不同的输入元素使用不同的属性并抛出不同的事件:
value
属性和 input
事件;checked
属性和 change
事件;value
作为 prop 并将 change
作为事件。跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
<div v-pre>
<p>111p>
<p>111p>
<p>111p>
div>
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
<span v-once>This will never change: {{msg}}span>
<div v-once>
<h1>commenth1>
<p>{{msg}}p>
div>
用axios请求数据(推荐使用)
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
使用方式
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then( (response)=> {
console.log(response);
})
.catch( (error)=> {
console.log(error);
});
axios.get("/user").then((response)=>{}).catch(err => throw err)
axios.请求方式(url [,{参数}]).then(response=>{}).catch(err=>{throw err})
axios 简写方式
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
}).then(response => {
if(response.status == 200){
console.log(response.data);
}
})
注意:在then的回调函数中尽量使用箭头函数,因为如果使用function的话,在函数里使用this指向的时候,这个this指向的是window对象,而我们一般在获取的时候希望这个this是指向Vue的实例的,这样才可以在这个实例上添加数据
用vue-resource请求数据
返回的也是一个promise对象
使用方式
// 可以直接写在Vue实例的methods对象中
getInfo() { // get 方式获取数据
this.$http.get('http://127.0.0.1:8899/api/getlunbo').then(res => {
console.log(res.body);
})
}
postInfo() {
var url = 'http://127.0.0.1:8899/api/post';
// post 方法接收三个参数:
// 参数1: 要请求的URL地址
// 参数2: 要发送的数据对象
// 参数3: 指定post提交的编码类型为 application/x-www-form-urlencoded
this.$http.post(url, { name: 'zs' }, { emulateJSON: true }).then(res => {
console.log(res.body);
});
}
jsonpInfo() { // JSONP形式从服务器获取数据
var url = 'http://127.0.0.1:8899/api/jsonp';
this.$http.jsonp(url).then(res => {
console.log(res.body);
});
}
RESTful 风格
接口的风格
一个URL地址就对应一个资源,对于资源不同的操作用请求方式来区分
传统接口的体现
http://xxxx.com/getallstudent
http://xxxx.com/addstudent
http://xxxx.com/deletestudent
http://xxxx.com/updatestudent
RESTFul 风格
http://xxxx.com/students get方式
http://xxxx.com/students/id get方式
http://xxxx.com/students/id delete方式
http://xxxx.com/studetns/id patch方式
响应式数据
<div id="app">
<p>
我叫{{p.name}}
<br>
我有辆{{p.car}}
<br>
我今年才{{p.age}}
p>
<button @click="btnAddAge">设置年龄button>
div>
const vm = new Vue({
el: "#app",
data: {
p: {
name: "zs",
car: "玛莎拉蒂"
}
},
methods: {
btnAddAge(){
// 给data中的对象动态新增的属性,不能够有响应式的效果,也就是说不能触发视图更新
// 如果想要有响应式效果
// 1. 就需要提前,在对象中先把属性声明好 在hcc中一开始就添加好age属性,哪怕不给值
// this.p.age = 18;
// 2. 如果确实需要动态的给p对象添加age属性,那么我们可以用到vue中提供的$set方法
// 这个方法,可以动态的给数据添加响应式的属性!
// this.$set(this.p, "age", 18);
// Vue.set(vm.p, "age", 18) // 这两个方法是一样的
// 数组通过索引直接修改索引对应的内容,是无法实现响应式的效果
// this.students[1] = {id: 2, name: "ls"};
// 需要用set来设置
// this.$set(this.students, "1", {id: 2, name: "ls"})
}
}
});
什么时候用$set??
当给对象动态添加属性的时候,需要用$set
当想要通过数组的下表给元素赋值的时候,需要用$set
异步数据更新
Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更
如果你想基于更新后的 DOM 状态来做点什么,可以在数据变化之后立即使用 Vue.nextTick(callback)
这样回调函数将在 DOM 更新完成后被调用
<div id="example">{{message}}div>
var vm = new Vue({
el: '#example',
data: {
message: '123'
}
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
vm.$el.textContent === 'new message' // true
})
// 也可以使用 vm.$nextTick
数据在vue实例上
我们是将数据放在参数对象中的data属性中传递给Vue构造函数的,Vue构造函数在接收到这个参数后