创建一个Vue应用
1.应用实例
每个Vue应用都是通过createApp函数创建一个新的应用实例
import { createApp } from 'vue'
const app = createApp({ //根组件选项})
2.根组件
若使用的是单文件组件,可直接从另一个文件中导入根组件
import {createApp } from 'vue'
import App from './App.vue'
const app=createApp(App)
3.挂载应用
实例对象必须调用 .mount()后才能渲染出来
<div id="app"></div>
app.mount('#app') //可以是一个实际的DOM元素或者一个CSS选择器字符串
4.根组件模板
<div id="app">
<button @click="count++">{{count}}</button>
</div>
import{creatApp} from 'vue'
const app=creatApp({
data(){
return{count:0}
}
})
app.mount("#app")
模板语法
1.文本插值 (大括号)
<span> Message : {{msg}} </span> //会将数据解释为纯文本
2.原始HTML(v-html)
<p> Using v-html direction: <span v-html="rawHtml"> </span> </p> //插入HTML
3.attribute绑定(v-bind)
双括号不能在HTML attribute中使用,要想响应式的绑定一个attribute,使用v-bind指令
<div v-bind : id="dynamicId"><div>
简写:<div :id="dynamicId"></div>
v-bind指令知识Vue将元素id attribute与组件dynamicId属性保持一致,如果绑定的值为null/undefined,则attribute将会在渲染元素上移出
(1)布尔型attribute:依据true/false来决定attribute是否应该存在该元素上
<button :disabled="isButtonDisabled">Button</button>
(2)动态绑定多个值 :通过不带参数的v-bind将一个包含多个attribute的JS对象绑定到单个元素上
data(){
return{
ObjectOfAttrs:{
id:" ",
class:" "
}
}
}
<div v-bind="objectOfAttrs"></div>
4.使用JavaScript表达式
在Vue模板中,JavaScript表达式可以使用在文本插值中和任何Vue指令attribute的值中。每个绑定仅支持单一表达式,一段能够被求值的JavaScript代码(能合法的写在return后面)
使用调用函数:<span :title="toTitlrDate(date)">{{formateDate(date)}}</span>
5.指令Direction
指令是一个带有v-前缀的特殊attribute,指令attribute的期望值为一个JavaScript表达式,一个指令的任务是在其表达式的值发生变化时响应的更新DOM
6.参数Arguments
动态参数中表达式的值应当是一个字符串或null,null意为显示移除该绑定,其他非字符串会触发警告动态参数语法的限制。
动态参数表达式因为某些字符的缘故有一些语法限制,比如空格和引号在HTML attribute名称中不合法,在使用DOM内嵌模板时名称大写字母会强制转换为小写
7.修饰符Modifiers
以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定
响应式基础
1.声明响应式状态(data)
选用选项API时,用data选项来声明组件的响应式状态,此选项值返回一个对象函数
export default{
data(){
return{
count:1}
},
mounted(){
console.log(this.count) //this指向当前组件实例
this.count=2
}
}
//实力上的属性仅在实例首次创建时被添加,所以要确保出现在data函数返回的对象上,可以用null | undefined 占位,若不在data定义,直接向组件实例添加新属性,该属性无法触发响应式更新
2.声明方法
Vue自动给methos中的方法绑定永远指向组件实例的this(methos中的方法不能用箭头函数,因为箭头函数没有自己的上下文)
3.DOM更新时机
若要等待一个状态改变后的DOM更新完成,可使用nextTick()这个全局变量
import { nextTick} from 'vue'
export default {method:{ increment() { this.count++
nextTick(()=>{})
}}}
4.深层响应式(Vue默认深层响应式)
export default { data() {
return{
obj:{ nested:{count:0},
arr:['foo','bar']
}}},
methods:{ mutateDeeply(){this.obj.nested.count++
this.obj.arr.push('baz')
5.有状态方法
要保证每个组件实例的方法函数都彼此独立,在created生命钩子中创建方法函数
eg:预制防抖的事件处理器的创建
import { debounce } from 'lodash-es'
export default{
methods:{click:debounce(function(){
//对点击的响应
}}
=>
export default {
created(){
this.debouncedClick=_.debounce(this,click,500)
},
unmounted(){//最好在组件卸载时清除掉防抖计时器
this.debouncedClick.cancel()
},
methods:{click(){//对点击的响应}
}
计算基础重点
export default{
data(){
return{
author:{
name:'John',
books:[
'A',
'B',
'C'
]
}
}
},
computed:{
publishedBooksMessage(){
return this.author.books.length>0?'Yes':'No'
}
}
}
<p>Has published books:<p>
<span<{{publishedBookMessage}}</span>
用计算属性缓存而不用方法的原因:
因为计算属性值会基于其响应式依赖被缓存,只有在其响应式依赖更新时才会重新计算,publishedBooksMessage依赖于this.author.books.length,只要author.books不发生改变,publishedBooksMessage都会立即返回先前的计算结果,但是方法调用总会在重新渲染发生时再次执行函数
可写计算属性
getter|setter
getter只做计算操作,避免直接修改计算属性值
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[this.firstName, this.lastName] = newValue.split(' ')
}
}
}
}
Class与Style绑定
1.绑定HTML class
(1)内联绑定对象
传递一个对象来动态切换class
data(){ return{ isActive:true, hasError:false } } <template> <div class="static :class="{active:isActive,'text-danger':hasError}"></div> </template>
渲染结果为:<div class="static active"></div>
(2)直接绑定对象
data(){ return{ classObject:{ active:true, 'text-danger':false } } } <template> <div :class=""classObject"></div> </template>
(3)绑定一个返回对象的计算属性
data(){ return{ isActive:true, error:null } }, computed:{ classObject(){ return{ active:this.isActive && !this.error, 'text-danger':this.error && this.error.type==='fatal' } } <template> <div :class=""classObject"></div> </template>
(4)绑定数组
data() { return { activeClass: 'active', errorClass: 'text-danger' } } <template> <div :class="[activeClass,errorClass]"></div> </template>
渲染结果:<div class="active text-danger"></div>
在数组中有条件的渲染某个class
1.三元表达式
<div :class="[isActive ? activeClass : '', errorClass]"></div>
2.数组中嵌套对象
<div :class="[{ active: isActive }, errorClass]"></div>
只有当isActive为真时,activeClass|active才会存在
(5)在组件上使用
//子组件 <p class="foo bar"></p> //使用组件 <MyComponent class="baz boo" /> //<p class="foo bar baz boo"></p> //class绑定 <MyComponent :class="{ active: isActive }" /> //当isActive为true时,<p class="foo bar active"></p> //组件有多个根元素时,用组件的$attrs属性来实现指定 <p :class="$attrs.class"></p> <span>This is a child component</span> <MyComponent class="baz" /> /*<p class="baz"></p> <span>This is a child component</span>*/
2.绑定内联样式
(1)直接绑定JavaScript对象值
data() { return { activeColor:"red", fontSize:30 } } <template> <div :style="{'font-size':fontSize+'px'}"></div> <div :style="{color:activeColor,fontSize:fontSize+'px'}"></div> </template>
(2)直接绑定一个样式对象
data(){ return{ styleObject:{ color:'red', fontSize:'13px' } } } <template> <div :style="styleObject"></div> </template>
(3)绑定返回样式对象的计算属性
(4)绑定数组
<template> <div :style="[baseStyles,overridingStyles]"></div> </template>
(5)自动前缀
可以通过给属性添加前缀来实现浏览器支持,可以对一个样式属性提供多个(不同前缀的)值,数组只会渲染浏览器支持的那个值
条件渲染
1.v-if
条件性的渲染一块内容,只有在指令表达式返回true时才会被渲染
<div v-if="awesome">awesome!</div>
2.v-else
必须在v-if | v-else-if后面使用
<button @click="awesome = !awesome">Toggle</button> <h1 v-if="awesome">返true</h1> <h1 v-else>返false</h1>
3.v-else-if
必须在v-else-if | v-if后面使用
4.在<template>上添加v-if | v-else |v-else-if
用来切换多个元素
<template v-if | v-else |v-else-if =""> ... </template>
5.v-show
v-show会在DOM渲染中保留该元素,仅切换了该元素上display属性,无论初始条件如何,始终都会被渲染。
列表渲染
1.v-for基于数组渲染列表
data() { return { items: [{ message: 'Foo' }, { message: 'Bar' }] } } <template> <li v-for="item in items"> {{ item.message }} </li> </template> /* 输出结果:Foo Bar*/
item为迭代项别名,items为源数据的数组
也可以完整访问父作用域内的属性和变量
data() { return { parentMessage: 'Parent', items: [{ message: 'Foo' }, { message: 'Bar' }] } } <template> <li v-for="(item, index) in items">{{ parentMessage }} - {{ index }} - {{ item.message }}</li> </template> /*输出结果 Parent-0-Foo Parent-1-Bar*/
2.v-for 遍历对象所有属性
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
<template>
<li v-for="(value, key, index) in myObject"> {{ index }}. {{ key }}: {{ value }} </li>
</template>
/*输出:
0.title.How to do lists in Vue
1.author.'Jane Doe'
2.publishedAt.2016-04-10
*/
3. v-for中使用范围
n的初值是从1开始而不是0,v-for也可以用在<template>上使用来渲染一个包含多个元素的块
<template> <span v-for='n in 10'>这是第{{n}}次循环</span> </template>
4.v-for与v-if
v-if 和 v-for同时存在在一个元素上的时候,优先执行v-if,这意味着v-if的条件无法访问到v-for作用域内定义的变量别名,解决办法,在该元素外面新包装一层<template>,将v-for定义在其上
5.通过key管理状态
给每个元素对应的块提供一个唯一的key attribute来跟踪每个节点的标识,从而重用和重新排序现有的元素
<div v-for="item in items" :key="item.id"></div>
注意事项:v-for在循环时,key只能使用number获取string
key在使用时只能使用x-bind的属性绑定的形式指定key值
推荐在v-for时就提供key attribute
6.在组件上使用v-for
因为组件有自己独立的作用域,在组件上使用v-for时除key还需要传递需要传递的数据
<MyComponent v-for="(item, index) in items" :item="item" :index="index" :key="item.id" />
7.数组变化侦测
首先找出能够改变数组自身的数组api,再使用自定义函数覆盖
(1)变更方法
分别是:push、pop、shift、unshift、splice、sort、reverse,能变更原始数组,页面上的数据会发生同步变化,
替换一个数组
(2)替换一个数组
filter()、concat()、slice()不会变更原始数组,所以页面上的数据不会发生同步变化
8.展示过滤或排序后的结果
(1)通过计算属性来获得过滤或排序后的数组(使用reverse()和sort()时因为会变更原始数组,多以调用前需创建一个原数组的副本)
export default { data() { return { sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]] } }, methods: { even(numbers) { return numbers.filter(number => number % 2 === 0) } } } <template><li v-for="n in evenNumbers">{{ n }}</li></template>
(2)通过 method方法
export default { data() { return { sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]] } }, methods: { even(numbers) { return numbers.filter(number => number % 2 === 0) } } } <template><ul v-for="numbers in sets"><li v-for="n in even(numbers)">{{ n }}</li></ul></template>
事件处理
1.监听事件
v-on指令
2.内联事件处理器
事件被触发时执行的内联js语句
export default { data() { return { count: 0 } } } <template><button @click="count++">{{count}}</button></template>
在内联处理器中调用方法
export default{ methods: { say(message){ alert(message) } } } <template> <button @click="say('hi')">Say hi</button> </template>
在内联事件处理器中访问事件参数
methods: { warn(message, event) { if (event) { event.preventDefault() } alert(message) } }
1.传入$event变量
<button @click="warn('a', $event)">Submit</button>
2.使用内联箭头函数
<button @click="(event) => warn('a', event)">Submit</button>
3.方法事件处理器
v-on接受一个方法名或某个方法的调用
export default{
data(){
return{
name:'cc'
}
},
methods:{
A(event){
alert('Hello ${this.name}!')
if(event){
alert(..)
}
}
}
}
<template><button @click='A'>A</button></template>
4.事件修饰符
v-on的事件修饰符。
.stop 阻止冒泡 .prevent 阻止默认事件
.capture 添加事件侦听器时使用事件捕获模式
.self 只当事件在该元素本身(不是子元素)触发时回调 .once 事件只触发一次 .passive 提前告诉浏览器,未使用阻止默认事件(event.preventDefault()) 格式:<a @click.stop="doThis"></a>
可以链式书写:<a @click.stop.prevent=" " ></a> | <a @click.stop.prevent></a>
(要注意顺序,@click.prevent.self会阻止元素及其子元素的所有点击事件的默认行为,而@click.self.prevent只会阻止元素本身的点击事件默认行为)
5.按键修饰符
Vue允许为v-on在监听键盘事件时添加按键修饰符
<input @keyup.enter="submit"/> /*仅在key为Enter时调用submit*/
.enter 回车确认键 .up 上 .tab TAB键 .down 下 .delete 捕获“删除”和“退格”键 .left 左 .esc Esc取消键
.right 右 .space 空格键 系统按键修饰符 .alt .shift .meta 在Mac键盘中是Command键,在Window键盘上是Windows键 .ctrl 系统修饰符只有当按键被按下时才会触发
<!-- Alt + Enter --> <input @keyup.alt.enter="clear" /> <!-- Ctrl + 点击 --> <div @click.ctrl="doSomething">Do something</div>
6. .exact修饰符
.exact修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 --> <button @click.ctrl="onClick">A</button> <!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- 仅当没有按下任何系统按键时触发 --> <button @click.exact="onClick">A</button>
7.鼠标按键修饰符
.left | .right | .middle |
表单输入绑定(v-model)
前端处理表单时,将表单输入框的内容同步给JavaScript中对应的变量,可以通过v-model指令简化手动连接值绑定和更改事件监听器的过程。v-model始终将当前绑定的JavaScript状态视为数据的正确来源,会忽略任何表单元素上初始的value、checked和selected attribute。
<input :value="text" @input="event => text=event.target.value">
简化后:<input v-model="text">
v-model可以用于各种不同类型的输入,会根据所使用的元素自动使用对应的DOM属性和事件组合:
- 文本类型的<input>和<textarea> 元素会绑定value property 并侦听input事件;
- <input type="checkbox">和<input type="radio"> 会绑定checked property 并侦听change事件;
- <select>会绑定value property 并侦听change事件
1. 基本用法
文本:<p>Message is :{{message}}</p>
<input v-model="message" placeholder="write in" />
多行文本: <span>Multilie message is:</span>
<p style="white-space:pre-line;">{{message}}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
<textarea>中不支持插值表达式的,用v-model=" "来代替
复选框:
1.单一复选框
export default { data() { return { checked: true } } } <template> <input type="checkbox" id="checkbox" v-model="checked" /> <label for="checkbox">{{ checked }}</label> </template> /*勾选返true,取消勾选返false*/
2.多个复选框绑定到同一个数组或集合的值
export default { data() { return { checkedNames: [] } } } <template> <div>Checked names: {{ checkedNames }}</div> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames" /> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames" /> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames" /> <label for="mike">Mike</label> </template>
单选按钮
export default { data() { return { picked: 'One' } } } <template> <div>Picked: {{ picked }}</div> <input type="radio" id="one" value="One" v-model="picked" /> <label for="one">One</label> <input type="radio" id="two" value="Two" v-model="picked" /> <label for="two">Two</label> </template>
选择器
1.单个选择器
export default { data() { return { selected: '' } } } <template> <span> Selected: {{ selected }}</span> <select v-model="selected"> <option disabled value="">Please select one</option> <option>A</option> <option>B</option> <option>C</option> </select> </template>
2.多选(将值绑定到一个数组中)
export default { data() { return { selected: [] } } } <template> <div>Selected: {{ selected }}</div> <select v-model="selected" multiple> <option>A</option> <option>B</option> <option>C</option> </select> </template>
3.用v-for动态渲染选择器选项
export default { data() { return { selected: 'A', options: [ { text: 'One', value: 'A' }, { text: 'Two', value: 'B' }, { text: 'Three', value: 'C' } ] } } } <template> <select v-model="selected"> <option v-for="option in options" :value="option.value"> {{ option.text }} </option> </select> <div>Selected: {{ selected }}</div> </template> /*选One显示A*/
2.值绑定
对于单选按钮、复选框和选择器选项,v-model绑定到值通常是静态的字符串(复选框为布尔值),可以用v-bind来实现将值绑定到当前组件实例上的动态数据以及将选项值绑定为非字符串的数据类型
<!-- `picked` 在被选择时是字符串 "a" -->
<input type="radio" v-model="picked" value="a" />
<!-- `toggle` 只会为 true 或 false -->
<input type="checkbox" v-model="toggle" />
<!-- `selected` 在第一项被选中时为字符串 "abc" -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
(1)复选框
<input
type="checkbox"
v-model="toggle"
//true-value="yes"
:true-value="dynamicTrueValue"
// false-value="no"
:false-value="dynamicFalseValue" />
//toggle属性的值被选中时为yes,取消选中时为no
/*true-value和false-value是Vue特有的attributes*/
(2)单选按钮
<input type="radio" v-model="pick" :value="first" />
<input type="radio" v-model="pick" :value="second" />
//pick 会在第一个按钮选中时被设为first,第二个按钮选中时设为second
(3)选择器选项
<select v-model="selected">
<!-- 内联对象字面量 -->
<option :value="{ number: 123 }">123</option>
</select>
//当某个选项被选中,selected会被设为该对象字面量值{number:123}
3.修饰符
(1).lazy
默认情况下,v-model会在每次input事件后更新数据,可以通过.lazy来改为在每次change事件后更新数据
<!-- 在 "change" 事件后同步更新而不是 "input" --> <input v-model.lazy="msg" />
(2).number
让用户输入自动转换为数字,若该值无法被parseFloat()处理,则返回原始值,number修饰符会在输入框有type="number"时自动启用
<input v-model.number="age" />
(3).trim 使默认自动去除用户输入内容中两端的空格
<input v-model.trim="msg" />
侦听器
watch选项:在每次响应式属性发生变化时触发一个函数
侦听器侧重监听单个数据的变化,最终执行特定的业务处理,不需要任何返回值,如果需要一般将结果赋值给另外一个变量
(1)简单侦听器
不能人为调用,只要侦听的数据发生变化就会自动触发
watch:{
//定义侦听函数
想侦听的属性名称(新值,旧值){
..
}
(2)深层侦听器
侦听所有嵌套的变更,深度侦听需要遍历被侦听对象中的所有嵌套的属性。
export default {
watch: {
someObject: {
handler(newValue, oldValue) {
// 注意:在嵌套的变更中,只要没有替换对象本身,那么这里的 `newValue` 和 `oldValue` 相同
},
deep: true
}
}
}
(3)即时回调侦听器(immediate选项)
运用handler方法和immediate:true选项强制回调函数立即执行,
export default {
// ...
watch: {
//侦听question属性值的变化
question: {
handler(newQuestion) {
// 在组件实例创建时会立即调用
},
// 强制立即执行回调
immediate: true
}
}
// ...
}
(4)回调的触发时机(flush:'post')
默认情况下,用户创建的侦听器回调都会在Vue组件更新之前被调用,而flush:'psot'选项可以使在更新之后被调用
export default {
watch: {
key: {
handler() {},
flush: 'post'
}
}
}
(5)this.$watch()
运用组件实例的$watch()来命令式的创建一个侦听器
export default {
created() {
this.$watch('question', (newQuestion) => {
// ...
})
}
}
(6)停止侦听器
少数情况下需要在组件卸载之前就停止一个侦听器,通过调用$watch() API返回的函数来停止侦听器
const unwatch = this.$watch('foo', callback)
// ...当该侦听器不再需要时
unwatch()
(7)deep选项
当watch侦听的是一个对象,如果对象中的属性值发生变化,则无法被监听到,可以通过deep选项来侦听
watch:{
obj:{
handler(){
..//当监听的属性值发生变化时
},
//用来侦听指定对象中的属性值变化
deep:true
}
模板引用(ref)
ref是一个特殊的attribute,它允许我们在一个特定的DOM元素或者子组件实例被挂载后,获得对它的直接引用。
<input ref='input'>
(1)访问模板引用(this.$refs)
只有在组件挂载结束后才能访问模板引用,如果在模板表达式上访问$refs.input,因为为初次渲染,所以为null
this.$refs.input.focus()
(2)在v-for上的引用
在v-for中使用模板引用,相应的引用中包含的值是一个数组
<script>
export default {
data() {
return {
list: []
}
},
mounted() {
console.log(this.$refs.items)
}
}
</script>
<template>
<ul><li v-for="item in list" ref="items">{{ item }}</li></ul>
</template>
(3)函数模板引用
<input :ref="(el) => { /* 将 el 赋值给一个数据属性或 ref 变量 */ }">
(4)加在组件上
调用子组件的methods,修改子组件的data