本文参考了vuejs的官方文档,结合自己的理解整理而成的读书笔记!
vuejs响应式的将data里声明的数据和Dom建立联系,可以非常方便的设置和获取Dom对象绑定的值
<div id="app">
<p>{{ message }}</p>
// v-bind将html原生属性title和message变量绑定, v-bind可简写为 :
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
var app = new Vue({ //创建vue实例对象app,每一个Vue应用都是从实例化一个Vue实例开始的
el: '#app', //声明此vue实例将要挂载的Dom元素ID
data: {
message: 'Hello Vue!' + new Date().toLocaleString() //声明响应式数据message
}
})
// 所有的 Vue 组件都是 Vue 实例,并且接受相同的选项对象 (一些根实例特有的选项除外)
// 当一个 Vue 实例被创建时,只有data 中存在的属性才是响应式的。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值
// 如果对data中的属性使用 Object.freeze(),这会导致响应系统无法再追踪该属性变化
// Vue 将模板编译成虚拟 DOM 渲染函数,结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少
条件的成立与否可以用来控制Dom的显示与隐藏
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
new Vue({
el: '#demo',
data: {
show: true
}
})
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
// v-if的表达式为false时,Dom结构从html文档中删除了,并不是display为none的效果
// 这里v-if还结合了Dom元素的过渡效果,利用transition标签和fade类对应的css效果实现了Dom元素的渐入和淡出效果
v-for 指令可以绑定数组的数据来渲染一个项目列表
处理用户输入,我的理解是监听Dom事件来做出相应的响应,在Vue中用v-on(可简写为@) 指令添加一个事件监听器
为了使大型的应用能够更好的解耦,组件化是非常有必要的,这样我们可以独立出可复用的相同功能的组件来达到减少代码量并合理解耦父子组件的目的
- Vue 组件实现了 Slot API 与 is 特性
- Web 组件规范仍然处于草案阶段,并且未被所有浏览器原生实现。相比之下,Vue 组件不需要任何 polyfill,并且在所有支持的浏览器 (IE9 及更高版本) 之下表现一致。必要时,Vue 组件也可以包装于原生自定义元素之内
- Vue 组件提供了纯自定义元素所不具备的一些重要功能,最突出的是跨组件数据流、自定义事件通信以及构建工具集成
vue里面使用{{}}实现html结构中的文本插值,好像没有angularjs里面的可自定义插值语法的接口,给标签或者组件使用v-once指令可以实现一次性的插值,当绑定的数据发生响应式变化时,也不会更新Dom
v-html指令可以将变量保存的html内容替换到Dom中直接作为 HTML,会忽略解析属性值中的数据绑定,不能使用 v-html 来复合局部模板,因为 Vue 不是基于字符串的模板引擎,组件更适合作为可重用和可组合的基本单位
绝不要对用户提供的内容使用HTML插值,因为它很容易导致 XSS 攻击(测试了一下,好像不能在变量里写script标签)
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护
"example">
Full Name: "{{ fullName }}"
Original message: "{{ message }}"
{{ message.split('').reverse().join('') }}
// 这里的插值表达式,一个是计算属性一个是执行方法,动态更新依赖message的值,计算属性重新执行了一次,而方法重新执行了两次
Computed reversed message: "{{ reversedMessage }}"
Computed reversed message: "{{ reversedMessage }}"
Computed reversed message: "{{ reversedMessageFunc() }}"
Computed reversed message: "{{ reversedMessageFunc() }}"
var vm = new Vue({
el: '#example',
data: {
message: 'Hello',
firstName: 'dao',
lastName: 'keer'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
console.log("computed reversedMessage")
return this.message.split('').reverse().join('')
},
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
},
methods: {
reversedMessageFunc: function () {
// `this` 指向 vm 实例
console.log("reversedMessageFunc reversedMessage")
return this.message.split('').reverse().join('')
}
}
})
// 上面的插值表达式,很明显的使用计算属性比一长串表达式要来的更清晰,后续也更好维护,不用频繁的去Dom结构中查看表达式的写法
// 所以说相对复杂的插值表达式最好用计算属性来代替
// 计算属性是基于它们的依赖进行缓存的,计算属性只有在它的相关依赖发生改变时才会重新求值
// 只要计算属性依赖的变量没有发生改变,多次访问计算属性会立即返回之前的计算结果,如果不希望有缓存,请用方法来替代
// 试图去修改计算属性:[Vue warn]: Computed property 'reversedMessage' was assigned to but it has no setter.
// 不过在需要时你也可以提供一个 setter,动态修改fullName的值set函数里面也修改了firstName和lastName的值
"demo">{{ fullName }}
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
},
// 下面这种监听,最好改造为上面的计算属性的形式,因为下面这种写法就表明了fullNmae是依赖于firstNane和lastName的,计算属性更适合做这个
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
// Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性(watch)。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch
// 通常更好的做法是使用计算属性而不是命令式的 watch 回调
Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
p>
<p>{{ answer }}p>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js">script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js">script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
// 监听指定变量的变化,然后自定义handle函数
// 如果改写成计算属性的模式不是很优雅(对于设置中间状态实现比较难控制),关于异步回调的结果还需要额外的变量来缓存,然后通过计算属性属性来返回
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于`_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api').then(function (response) {
vm.answer = _.capitalize(response.data.answer)
}).catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
script>