安装 |
初期选择直接嵌入
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
|
声明式渲染 |
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
|
条件与循环 |
● v-if
参数为真时显示
<div id="app-3">
<p v-if="seen">现在你看到我了</p>
</div>
var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})
● v-for
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
]
}
})
|
处理用户输入 |
● v-on 绑定事件
例: v-on:click
<div id="app-5">
{{message}}
<button type="button" v-on:click='reserveMsg'>反转文本</button>
</div>
var app5 = new Vue({
el: '#app-5',
data: {
message: 'sample'
},
methods: {
reserveMsg: function() {
console.log(this);
let msg = this.message;
msg = this.message.split('').reverse().join('');
this.message = msg;
}
}
});
● v-model
表单输入和应用状态之间的双向绑定
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})
|
组件化应用构建 |
● 注册组件
Vue.component(组件名, 组件内容)
例
// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
template: '<li>这是个待办项</li>'
})
<ol>
<!-- 创建一个 todo-item 组件的实例 -->
<todo-item></todo-item>
</ol>
● 设计例
<div id="app">
<app-nav></app-nav>
<app-view>
<app-sidebar></app-sidebar>
<app-content></app-content>
</app-view>
</div>
|
Vue实例 |
创建一个vue实例 |
var vm = new Vue({
// 选项
})
|
数据与方法 |
所有属性都以 $ 开头
data |
视图更新 |
● data对象的所有属性自动加入到响应式系统
● data对象(及其指向的对象)若发生变化, 视图会更新
● 只监视创建时就存在的属性
● Object.freeze(...) 冻结的不监视
|
|
|
|
|
|
|
|
|
|
|
|
|
声明周期钩子 |
● vue实例创建前后的处理
设置数据监听
|
|
编译模板
|
|
将实例挂载到 DOM 并在数据变化时更新 DOM |
|
● 可挂载的钩子
beforeCreate |
|
created |
|
beforeMount |
|
mounted |
|
beforeUpdated |
|
updated |
|
beforeDestroy |
|
|
|
|
|
|
|
|
声明周期图 |
|
|
|
template语法 |
插值 |
文本 |
输出为纯文本
|
原始html |
作为html输出
例
<span v-html="rawHtml"></span>
|
属性 |
绑定属性
● true/false时
自动转换为false的值: null, undefined, false
备注: js转换为false: https://www.cnblogs.com/lancgg/p/10405214.html
|
JavaScript表达式 |
插值支持JavaScript表达式
● 单个插值只能包含一个表达式
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
|
|
指令 |
所有指定以 v- 开始
v-once: 当前节点为根的节点树不会更新插值内容
参数 |
有些指令能接收一个参数
● 例
<a v-bind:href="url"> ... </a>
<a v-on:click="doSomething">...</a>
|
动态参数 |
[JavaScript表达式]
● 要求
字符串. 除了 null ,用于移除绑定. 其他的都会触发警告
● 例
<a v-bind:[attributeName]="url"> ... </a>
<a v-on:[eventName]="doSomething"> ... </a>
|
修饰符 |
用 . 连接在指定最后 例
<form v-on:submit.prevent="onSubmit"> ... </form>
表示呼出 event.preventDefault()
|
|
缩写 |
● v-bind
<!-- 完整语法 -->
<a v-bind:href="url"> ... </a>
<!-- 缩写 -->
<a :href="url"> ... </a>
<!-- 动态参数の省略写法 (2.6.0 以后) -->
<a :[key]="url"> ... </a>
● v-on
<!-- 完整语法 -->
<a v-on:click="doSomething"> ... </a>
<!-- 缩写 -->
<a @click="doSomething"> ... </a>
<!-- 动态参数の省略写法 (2.6.0 以后) -->
<a @[event]="doSomething"> ... </a>
|
|
|
计算属性和侦听器 |
计算属性 |
基础例 |
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
|
setter |
// ...
computed: {
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]
}
}
}
// ...
|
和method的比较 |
计算属性在新计算后会缓存, 不会重复运算 |
和侦听属性的比较 |
一般用计算属性 |
|
|
|
侦听器 |
watch: {
对应属性名: function() {
...
}
}
|
|
|
class与style的绑定 |
绑定Class |
对象语法 |
● 可以是data, props, computed
● 属性名是class名, 属性值是false则不添加
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
data: {
isActive: true,
hasError: false
}
|
数组语法 |
● 每一个元素添加一个class
● 元素可以是object
<p v-bind:class="['a', 'b', 'c', {d: true, e: true, f: false}]">
sample_class2: array
</p>
|
用在组件上 |
# TODO: finish here |
|
绑定内联Style |
对象语法 |
● 可以是data, props, computed
● 和正常stylesheet差不多, 属性名可用驼峰写法( fontSize )和短横线( 'font-size' )写法
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
|
数组语法 |
● 放置多个object
<div v-bind:style="[baseStyles, overridingStyles]"></div>
|
自动添加前缀 |
当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。
https://cn.vuejs.org/v2/guide/class-and-style.html
|
多重值 |
● 可以给属性提供数组(多个值), 会选用浏览器支持的最后一个值
<p v-bind:style="[{'font-size': '100px'}, {display: ['a', 'none']}]">
sample_style:object
</p>
|
|
|
|
条件渲染 |
v-if |
v-if , v-else-if , v-else
● 条件为真时渲染代码块
● 如果要对多个元素使用条件, 可以包裹到 <template></template>
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
● 可以给元素设置唯一key, 有key的元素不会被混着重复利用
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
|
v-show |
条件为false时, 添加 display: none
● 不支持template, v-else, v-else-if
|
v-if vs v-show |
一般来说, v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
v-if |
● “真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
● 惰性(LazyLoad)的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
|
v-show |
一律被渲染, false的添加 display: none
|
|
v-if与v-for一起使用 |
不要一起使用, 改用计算属性等计算好以后再v-for
传送门
|
|
|
列表渲染 |
v-for对数组map |
写法:
第二参数支持索引
v-for="(item, index) in items"
例:
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
|
v-for对对象 |
第二参数支持key名, 第三参数支持索引
v-for="value in object"
// 带key名
v-for="(value, name) in object"
// 带key名和索引
v-for="(value, name, index) in object"
注: 枚举顺序为 Object.keys() 的顺序, 参考: https://www.cnblogs.com/lancgg/p/10403527.html
例:
<table>
<tr v-for="(v, k, i) in sampleData">
<td>{{k}}</td>
<td>{{i}}</td>
<td>{{v}}</td>
</tr>
</table>
sampleData: {
a: 'here is a',
b: 'here is b',
c: 'here is c'
}
|
维护状态 |
默认就地更新: 元素被改变了则更新元素而不是改变顺序匹配元素
加上key属性, 是的vue可以追踪
|
数组更新检测 |
● 被监视的变更数组的方法
copyWithin |
X |
fill |
X |
push |
◯ |
pop |
◯ |
shift |
◯ |
unshift |
◯ |
splice |
◯ |
sort |
◯ |
reverse |
◯ |
● 对于不变更数组的方法, 把数组设置成相关方法的返回值
Vue只能识别, 只重新渲染需要的
● 注: Vue不能识别如下变更方法
利用索引直接设置
vm.items[indexOfItem] = newValue
|
解决方法
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set是别名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
|
直接修改数组长度
vm.items.length = newLength
|
解决方法
vm.items.splice(newLength)
|
|
|
|
对象更新检测注意事项 |
Vue不能检测对象属性的添加或删除, 对现存属性的修改可以感应到
解决方法:
Vue.set(object、propertyName、value) vm.$set(vm.userProfile, 'age', 27)
● 合并object, 不要直接使用 Object.assign() , _.extend()
不要这样
Object.assign(vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
要这样
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
|
显示过滤/排序后的结果 |
不变更原数组, 只是表示的话用计算属性
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
|
在v-for里使用值范围 |
v-for接受整数
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
|
template的v-for |
和 v-if 一样, 可以对template使用 v-for
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
|
v-for与v-if |
不要一起用 |
组件与v-for |
# TODO: finish here |
|
|
监听事件 |
监听事件 |
例
<div id="example-1">
<button v-on:click="counter += 1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0
}
})
|
事件处理方法 |
可以添加method, 然后事件触发时呼出
呼出方法:
@事件名="方法名"
// 例
@click="clickHander"
例
<div id="example-2">
<!-- `greet` 是在下面定义的方法名 -->
<button v-on:click="greet">Greet</button>
</div>
|
内联处理器中的方法 |
也可以用式子来呼出方法
<button type="button" name="button" @click="msg('app-12')">
click me
</button>
|
事件修饰符 |
.stop |
阻止事件传播, event.stopPropagation()
例:
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
|
.prevent |
阻止默认事件, event.preventDefault()
例:
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
|
.capture |
在传导阶段就触发
例:
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
|
.self |
事件只对自身触发
例:
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
|
.once |
事件只触发一次, 可对所有事件生效
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
|
.passive |
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
不要和prevent一起用
|
|
|
● 可以不指定值, 只是用装饰符
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
● 修饰符可以串联
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
● 使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。
因此,用 v-on:click.prevent.self 会阻止所有的点击,
而 v-on:click.self.prevent 只会阻止对元素自身的点击。
|
按键修饰符 |
# TODO: finish here |
系统修饰符 |
# TODO: finish here |
为什么在 HTML 中监听事件? |
# TODO: finish here |
|
|
表单绑定输入 |
基础用法 |
可用 v-model 在表单 <input> , <textarea> , <select> 上创建双向数据绑定
● v-model 会忽略所有表单元素的 value 、 checked 、 selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。
即Vue会忽略html设定的表单值
你应该通过 JavaScript 在组件的 data 选项中声明初始值。
● v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
<input type="text>
<textarea>
|
value属性
input事件
● text
<p>text_input: {{text_input}}</p>
<input v-model="text_input" placeholder="sample input"></input>
● textarea
<p>textarea_input: {{textarea_input}}</p>
<textarea name="name" placeholder="textarea_input" v-model="textarea_input"></textarea>
|
<input type="checkbox">
<input type="radio">
|
checked属性
change事件
● checkbox
- 单个: boolean值 checked=true/false
<input type="checkbox" v-model="checkbox_input"></input>
- 多个: 数组, value和值的比较是 ==
<p>checkbox_input: {{checkbox_input}}</p>
<input type="checkbox" v-model="checkbox_input" value="1"></input>
<input type="checkbox" v-model="checkbox_input" value="2"></input>
<input type="checkbox" v-model="checkbox_input" value="3"></input>
<input type="checkbox" v-model="checkbox_input" value="4"></input>
● radio
<p>radio_input: {{radio_input}}</p>
<input type="radio" name="radio_input" value="radio_a" v-model="radio_input"></input>
<input type="radio" name="radio_input" value="radio_b" v-model="radio_input"></input>
|
<select> |
value属性
change事件
● 单个
<p>single_select_input: {{single_select_input}}</p>
<select name="sampleSelect" v-model="single_select_input">
<option value="a">1</option>
<option value="b">2</option>
<option value="c">3</option>
</select>
● 多个
值是数组
<p>select_input: {{select_input}}</p>
<select name="sampleSelect" v-model="select_input" multiple>
<option value="a">1</option>
<option value="b">2</option>
<option value="c">3</option>
</select>
动态生成option
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
new Vue({
el: '...',
data: {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
})
|
● v-model的本质
<input v-model="searchText">
相当于
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
当用在自定义组件上时, 相当于
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
|
值绑定 |
v-bind:value="..." |
修饰符 |
lazy |
同步时机从input改为change |
number |
把输入转为数值
parseFloat()无法解析的取原值
|
trim |
从输入中取出空白 |
|
在组件上使用v-model |
# TODO: finish here |
|
|
组件基础 |
基本示例 |
组件是可复用的 Vue 实例,且带有一个名字
我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
● 除了根实例固有属性(如el), 组件与vue接收的属性属性一样
data, computed, methods, watch, 生命周期钩子等
|
组件的复用 |
注册的组件可以重复使用
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
● data必须是函数, 不然被共用
data: function () {
return {
count: 0
}
}
|
组件的组织 |
通常一个应用会以一棵嵌套的组件树的形式来组织
● 组件的注册方式:
|
通过Prop向子组件传递数据 |
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
|
单个根元素 |
每个组件必须只有一个根元素
|
监听子组件事件 |
抛出事件的方法
例
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>
● 访问事件抛出的值
当在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值 |
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>
|
如果处理函数是方法, 则会作为第一个参数 |
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
|
|
在组件上使用v-model |
● v-model的本质
<input v-model="searchText">
相当于
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
当用在自定义组件上时, 相当于
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
为了让它正常工作,这个组件内的 <input> 必须:
- 将其
value 特性绑定到一个名叫 value 的 prop 上
- 在其
input 事件被触发时,将新的值通过自定义的 input 事件抛出
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
|
通过插槽分发内容 |
在需要的地方加入插槽
|
动态组件 |
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>
|
解析DOM模板时的注意事项 |
有些 HTML 元素,诸如 <ul> 、<ol> 、<table> 和 <select> ,对于哪些元素可以出现在其内部是有严格限制的。
而有些元素,诸如 <li> 、<tr> 和 <option> ,只能出现在其它某些特定的元素内部。
|
|
|
|
|