Vue 学习笔记02—数据和方法Vue数据和方法(data,props,computed,watch …)
数据选项
- 1
数据(data) 选项可接受的类型有 对象 和 函数 两种,不过在 定义一个组件的时候只能使用函数类型。
示例:
<div id="app">
<h1>{{ title }}</h1>
<button-counter></button-counter>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
//全局注册组件
Vue.component('button-counter', {
// 创建一个Vue组件
data() {
// 必须使用函数类型
return {
counter: 1
}
},
template: '<button @click="counter++">clicked {{ counter }} times</button>'
})
// let vm = new Vue({
// el: '#app',
// // mount到DOM上
// data: {
// //对象类型
// title: 'A Vue App'
// }
// })
let vm = new Vue({
el: '#app',
// mount到DOM上
data() {
// 函数类型
return {
title: 'A Vue App'
}
}
})
</script>
- 2
Vue会递归的将 data 选项中的数据加入响应式系统,但是这些数据应该是声明的时候即存在的。
示例:
<div id="app" style="border: 1px black solid;">
{{ testValue }}
<br>
<Instance></Instance>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
// // 全局注册组件
// Vue.component('Instance', {
// // 创建一个Vue组件
// data() {
// // 必须使用函数类型
// return {
// title: "A Vue App"
// }
// },
// template: '<div><h2>{{ title }}</h2><p>{{ profile }}</p></div>'
// })
//局部注册组件
var Instance = {
template: '<div ><h2>{{ title }}</h2><p>{{ profile }}</p></div>',
data() {
return {
title: "A Vue App"
}
},
}
let vm = new Vue({
el: '#app',
components: {
Instance
},
// mount到DOM上
data() {
// 函数类型
return {
testValue: 'Vue'
}
},
created() {
Object.assign(this.$data, {
//为对象赋值属性,没有则添加属性,有则覆盖原有属性值
profile: "This is a Vue App"
});
console.log(this.$data);
}
})
</script>
注意: Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
语法: Object.assign(target, …sources)
target,目标对象。
sources,源对象。
(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
其中,title 是在初始化实例时声明在 data 选项中的数据,但是 profile 是在 created 钩子函数中被赋予 data 选项中的。
结果显示的是,profile 被赋予 data 选项之后,视图没有发生任何变化,并且控制台报错“ profile is not defined ”。原因是:1. 因为 Vue 在处理数据时,并未把 profile 加入到数据响应式系统中;2. profile 是在实例化创建完成后(即 created 执行完成后)被绑定到组件上的。此时的profile 只是一个普通的 JS 属性,而非被 Vue 观察的对象。
在 Vue 中,可以使用 $set 方法为 data 选项动态绑定数据,但是它也无法挂载数据到 $data 根节点上。
$set的用法:
target | key | value |
---|---|---|
目标对象 | 键名 | 键值 |
Obgect / Array | String / Number | 任意类型 |
// Vue.set (target, key, value)
created () {
this.$set (target, key, value);
}
应慎重地将已有内存地址的对象用于 data 选项,无论是以对象还是函数形式。
建议在声明时,不要将已有内存地址的对象用于 data 选项,应该创建新的对象。
无论选择哪种方式,都是为实例的 data 选项分配一个新的地址。
示例:
<div id="app">
<button-counter></button-counter> // 调用两次组件
<button-counter></button-counter>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
let jack = {
counter: 0
}
Vue.component('button-counter', {
data () {
// 深拷贝已有对象
return JSON.parse(JSON.stringify(jack))
// 定义新对象
// return {
// counter: 0
// }
},
template: '<button @click="counter++">click {{counter}} times</button>'
})
let vm = new Vue({
el: '#app' // mount到DOM上
})
</script>
属性选项
- 1
Vue 为组件开发提供了属性(props)选项,可以使用 props 为组件注册动态特性。
props 选项可以是数组、对象 类型,用于接收从 父组件 传递过来的参数,并允许开发者为其设置默认值、类型检测和校验规则等。
<div id="app">
<color-text text="Hello World"></color-text>
<br>
<color-text></color-text>
<br>
<color-text color="#f78" text="Hello World"></color-text>
<br>
<color-text color="#43dt" text="Hello World"></color-text>
<br>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
Vue.component('color-text', {
props: {
text: String,
color: {
type: String,
default: '#000', // 默认值黑色
required: true,
validator(value) {
// 校验规则,判断颜色值是否合法
return /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(value)
}
}
},
template: '<span :style="{ color: color}">{{ text }}</span>'
})
let vm = new Vue({
el: '#app'
})
</script>
方法选项
- 1
使用箭头函数定义方法:使用箭头函数定义方法时并不会创建函数作用域 ,因此 this 也不会指向其父级实例 ,此时的 this会向上追踪 。若是找到某个函数作用域时,this 将指向该函数的父级实例 ;否则 this 将指向浏览器的内置对象 Windows。
示例:
// 示例1:
let store_1 = {
msg: 'Hello World !',
logMsg: function () {
console.log('________匿名函数_____________');
console.log(this.msg);
}
}
store_1.logMsg();
let store_2 = {
msg: 'Hello World !',
logMsg: () => {
console.log('__________匿名函数____________');
console.log(this.msg);
}
}
store_2.logMsg();
// 示例2:
let store = {
msg: '学习已经很可怜了',
logMsg() {
let store = {
msg: '你能不能长点心',
logMsg: () => {
let store = {
msg: '给人多留点时间吧',
logMsg: () => {
console.log(this.msg)
}
}
store.logMsg()
}
}
store.logMsg()
}
}
store.logMsg()
- 2
关于methods 选项,不要用箭头函数在其中定义方法。
因为,在创建组件时,methods 中的方法将被绑定到 Vue 实例上,方法中的 this 也将自动指向 Vue 实例 。此时,若是使用箭头函数的话,this 将无法正确指向 Vue实例 。
计算属性
- 1
计算属性(computed)选项的设计可以在数据链上出现复杂衍生数据时使用其较易的去维护。是否使用 computed 选项对视图表现并无影响,但是使用了它之后,组件的代码结构会更加清晰,日后数据的处理方式发生了变化也只需要在选项中修改即可。
注意: 它与 methods 一样,computed 不能以箭头函数声明;同时,它也会被混入 Vue 实例,并可通过 this 调用。 - 2
计算属性依赖于响应式属性,所以当且仅当响应式属性变化时,计算属性才会被重新计算,而且得到的结果会被缓存,直到响应式属性再次被修改。 - 3
Vue 也允许开发者为 computed 属性赋值。开发者有权定义可被赋值的 computed 属性,方法类似于对象属性描述中的 setter 和 getter。
示例:(可在控制台中修改实例 message 值)
<div id="app">
<h2>数据变化之前
<i style="color: #ababab;font-size: 14px;">
* 指令v-once可以限制视图不再响应数据变化
</i>
</h2>
<p v-once>{{ message }}</p>
<p v-once>{{ noSpaceMsg }}</p>
<h2>数据变化之后</h2>
<p>{{ message }}</p>
<p>{{ noSpaceMsg }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data() {
return {
message: 'WAS IT A CAR OR A CAT I SAW'
}
},
computed: {
noSpaceMsg: {
set(value) {
this.message = value
},
get() {
return this.message.replace(/\s/g, '')
}
}
}
})
</script>
注.
-
v-once 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
-
通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。
-
通过 v-once 创建低开销的静态组件(不建议过度使用这个模式)
渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,你可以在根元素上添加 v-once attribute 以确保这些内容只计算一次然后缓存起来,就像这样:
Vue.component('terms-of-service', {
template: `
<div v-once>
<h1>Terms of Service</h1>
... a lot of static content ...
</div>
`
})
侦听属性
- 1
Vue 允许开发者使用侦听属性(watch 选项)为实例添加被观察对象,并在对象被修改时调用开发者自定义的方法。
watch
类型:{ [key: string]: string | Function | Object | Array }
详细:
一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个 property 。
示例:(使用 watch 重构定义可赋值的 computed 示例代码)
<div id="app">
<h2>数据变化之前
<i style="color: #ababab;font-size: 14px;">
* 指令v-once可以限制视图不再响应数据变化
</i>
</h2>
<p v-once>{{ message }}</p>
<p v-once>{{ noSpaceMsg }}</p>
<h2>数据变化之后</h2>
<p>{{ message }}</p>
<p>{{ noSpaceMsg }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data() {
return {
message: 'WAS IT A CAR OR A CAT I SAW',
// 如果允许被赋值,何不直接放在data中?
noSpaceMsg: 'WASITACARORACATISAW'
}
},
watch: {
// 使用watch实现:当元数据变化时,同步衍生数据的状态
message(newValue, oldValue) {
// newValue: 修改后的值, oldValue: 修改前的值
this.noSpaceMsg = this.message.replace(/\s/g, '')
}
}
})
</script>
- 2
watch 更注重于数据变化时的业务逻辑,而 computed 更注重于衍生数据。因此,与 computed 相比,watch 还优于异步修改数据。
示例:
// 使用 watch 选项为组件异步获取 ajax 请求的返回值
import axios from 'axios'
let vm = new Vue({
el: '#app',
data() {
return {
message: 'hello world',
remoteMsg: ''
}
},
watch: {
message(newValue, oldValue) {
axios({
// 发送 ajax 异步请求
method: 'GET',
url: '/someurl',
params: {
message: newValue
}
}).then(res => {
this.remoteMsg = res.data.message; //接收响应后,异步修改数据值
})
}
}
})
注意:不应该使用箭头函数来定义 watcher 函数
(例如 searchQuery: newValue => this.updateAutocomplete(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.updateAutocomplete 将是 undefined。
- 3
Vue 为 watch 选项提供了丰富的声明方式。例如:
// Vue 为 watch 选项提供了丰富的声明方式
let vm = new Vue({
el: '#app',
data() {
return {
msg: {
sender: 'Jack',
receiver: 'Rose'
}
}
},
methods: {
logLine() {
console.log('--------------------------');
},
logMsg(newValue, oldValue) {
console.log(newValue);
}
},
watch: {
msg: {
handler: 'logMsg', //方法名
deep: true, //深度观察:对象任何层级数据发生变化,watch 方法都会被触发
immediate: true //立即调用: 在侦听开始时立即调用一次 watch 方法
},
'msg.sender': ['logLine', 'logMsg'] //数组方式,可调用多个方法
}
})
——————END