一、类与样式绑定
1.1 绑定 HTML class
直接上例子 :
const isActive = ref(true)
const hasError = ref(false)
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
//最终
<div class="static active"></div>
当 isActive
或者 hasError
改变时,class 列表会随之更新。
也可以绑定一个对象或者绑定一个返回一个对象的计算属性:
const classObject = reactive({
active: true,
'text-danger': false
})
<div :class="classObject"></div>
=====================================
const isActive = ref(true)
const error = ref(null)
const classObject = computed(() => ({
active: isActive.value && !error.value,
'text-danger': error.value && error.value.type === 'fatal'
}))
<div :class="classObject"></div>
还可以绑定数组 还可以用三元表达式:
const activeClass = ref('active')
const errorClass = ref('text-danger')
<div :class="[activeClass, errorClass]"></div>
***************************************
三元表达式
<div :class="[isActive ? activeClass : '', errorClass]"></div>
errorClass 会一直存在,但 activeClass 只会在 isActive 为真时才存在。
还可以更复杂 如数组中嵌套对象
<div :class="[{ active: isActive }, errorClass]"></div>
1.2 在组件上使用
就是在组件上直接给一个class 属性
<MyComponent class=”baz boo” />
1.3 绑定内联样式
使用 :style 来实现内联样式添加
const activeColor = ref('red')
const fontSize = ref(30)
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
const styleObject = reactive({
color: 'red',
fontSize: '13px'
})
<div :style="styleObject"></div>
绑定数组也可以
<div :style=”[baseStyles, overridingStyles]”></div>
二、条件渲染
2.1 v-if v-else v-else-if
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。
你也可以使用 v-else
为 v-if
添加一个“else 区块”。
注:一个 v-else
元素必须跟在一个 v-if
或者 v-else-if
元素后面,否则它将不会被识别。
<button @click="awesome = !awesome">Toggle</button>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
v-else-if 和 v-else
类似,一个使用 v-else-if
的元素必须紧跟在一个 v-if
或一个 v-else-if
元素后面。
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
2.2 v-if 与 v-show
这两者的用法是一样的 但是实际渲染不一样
首先v-if 是真实的按条件渲染 因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建
v-show 简单许多 元素无论初始值条件如何 始终会被渲染 也就是css 中display的属性会被切换
总得来说 v-if的有高的切换开销 如果需要频繁的切换 v-show会好一点
注意:原则上v-if和v-for是不推荐同时使用的 如果同时存在的话 v-if会优先被执行
三、列表渲染
3.1 v-for
我们可以使用 v-for
指令基于一个数组来渲染一个列表。v-for
指令的值需要使用 item in items
形式的特殊语法,其中 items
是源数据的数组,而 item
是迭代项的别名:
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
<li v-for="(item,index)in items" :key='item.id'>
{{ item.message }}
</li>
在 v-for
块中可以完整地访问父作用域内的属性和变量。v-for
也支持使用可选的第二个参数表示当前项的位置索引。注意 我们还要加上一个key值 最好是id 等唯一值 最好不要index(可以用)
还可以渲染对象 遍历的顺序会基于该对象调用Object.keys() 的返回值来决定。
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
3.2 <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 同时使用的话 我们可以这样做
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
3.3 组件上使用 v-for
在组件中使用 v-for 别忘了提供一个key 如果数据传递给组件的话 需要传递props 如:
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
3.4 数组变化侦测
变更数组方法的有 :push() pop() shift() unshift() splice() sort() reverse()
还有一些方法是不会对原数组进行变更的 :filter()
,concat()
和 slice() 他们会返回一个新的数组
四、事件处理
4.1 使用方法
在vue中 我们用v-on指令来绑定监听dom事件 用法: v-on:click="methodName"
或 @click="handler"
。
在内联处理器中调用方法 允许我们向方法传入自定义参数以代替原生事件(e)
在内联事件处理器中访问事件参数 (两种方式 ):
<!-- 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
<!-- 使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
Submit
</button>
function warn(message, event) {
// 这里可以访问原生事件
if (event) {
event.preventDefault()
}
alert(message)
}
4.2 事件修饰符
vue提供了一些事件修饰符 .stop .prevent .self .capture .once .passive
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>
<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>
<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>
4.3 按键修饰符
vue提供了一些按键修饰符: .enter .tab .delete .esc .space .up .down .left .right
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />
<input @keyup.page-down="onPageDown" />
五、表单输入
5.1 利用 v-model 来监听值的变化
文本类型的 <input>
和 <textarea>
元素会绑定 value
property 并侦听 input
事件;
<input type="checkbox">
和 <input type="radio">
会绑定 checked
property 并侦听 change
事件;
<select>
会绑定 value
property 并侦听 change
事件。
复选框和单选框的使用方法 需要id和for来绑定 如:
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
*********************************************************
<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>
5.2 修饰符
vue提供了一些修饰符给我们 :
..lazy:v-model
会在每次 input
事件后更新数据 可以添加 lazy
修饰符来改为在每次 change
事件后更新数据
.number:
如果你想让用户输入自动转换为数字,可以在 v-model
后 .number
修饰符来管理输入:
.trim : 想要默认自动去除用户输入内容中两端的空格,你可以在 v-model
后添加 .trim
修饰符
六、生命周期
6.1 基础
每个vue组件实例在创建时都需要经历一系列的初始化步骤 类似于出生到死亡。
主要有以下生命钩子 :beforeCreate created beforeMount(还没创建dom节点) mounted(常用) beforeUpdate updated(常用)
beforeUnmount unmounted(常用) errorCaptured
vue 官方图示
七、侦听器 Watch
7.1 基础用法
可以用侦听器来侦听一个ref的变化 并触发相应的回调函数的逻辑 例子:
<script setup>
import { ref, watch } from 'vue'
const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')
// 可以直接侦听一个 ref
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.indexOf('?') > -1) {
answer.value = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
answer.value = (await res.json()).answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
}
}
})
</script>
<template>
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</template>
7.2 侦听数据源类型
watch
的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组,注意,你不能直接侦听响应式对象的属性值,例如:
const x = ref(0)
const y = ref(0)
// 单个 ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// getter 函数
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})
//不能直接侦听响应式对象的属性值
const obj = reactive({ count: 0 })
// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
console.log(`count is: ${count}`)
})
//正确做法是
// 提供一个 getter 函数
watch(
() => obj.count,
(count) => {
console.log(`count is: ${count}`)
}
)
7.3 深层侦听器
直接给 watch()
传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发。可以加上一个deep 选项 强制转成深层侦听器:
watch(
() => state.someObject,
(newValue, oldValue) => {
// 注意:`newValue` 此处和 `oldValue` 是相等的
// *除非* state.someObject 被整个替换了
},
{ deep: true }
)
7.4 即时回调的侦听器
watch
默认是懒执行的:仅当数据源变化时,才会执行回调。但是在某些业务场景下 需要我们在创建侦听器的时候 立即执行一遍回调。比如我们想请求一些初始数据 然后在相关状态更改时重新请求数据。我们可以传入 immediate: true
选项来强制侦听器的回调立即执行
watch(source, (newValue, oldValue) => {
// 立即执行,且当 `source` 改变时再次执行
}, { immediate: true })
7.5 watchEffect()
watcheffect() 函数可以让我们自动跟踪回调的响应式依赖 所以不需要指定 immediate:true。
如果你需要侦听一个嵌套数据结构中的几个属性,watchEffect()
可能会比深度侦听器更有效,因为它将只跟踪回调中被使用到的属性,而不是递归地跟踪所有的属性。对于有多个依赖项的侦听器来说 使用这个 可以消除手动维护依赖列表的负担。
watch
vs. watchEffect
watch 只追踪明确侦听的数据源 它不会追踪任何在回调中访问到的东西 而且只有数据源改变时才会触发
watcheffect 它会在同步执行过程中 自动追踪所有能访问到的响应式属性 可以立即执行一遍