vue3
模板语法
1、动态参数
<!-- 动态参数 -->
<!-- 如果你的组件实例有一个数据属性 attributeName,其值为 "href",那么这个绑定就等价于 v-bind:href -->
<a :[a.href]="a.url">百度一下</a>
<!-- 自定义绑定事件名 -->
<a @[eventName]="doSomething">{{ count }}点击加1</a>
data () {
return {
rawHtml: '<span style="color: red">This should be red.</span>',
href: 'href',
a: {
href: 'href',
url: 'http://www.baidu.com'
},
eventName: 'click'
};
},
methods: {
doSomething() {
console.log(1)
}
}
响应式基础
1、reactive()
<template>
<div>
<div>{{ state.count }}</div>
<button @click="addCount">点击count累加</button>
</div>
</template>
<script setup>
import { reactive } from 'vue';
export default {
setup() {
// 利用reactive设置响应式数据
const state = reactive({ count: 0 })
// 使count++的函数
function addCount() {
state.count++
}
// 暴露state,addCount
return {
state,
addCount
}
}
}
</script>
2、<script setup>
-
在
setup()函数中手动暴露大量的状态和方法非常繁琐。幸运的是,我们可以通过使用构建工具来简化该操作。当使用单文件组件(SFC)时,我们可以使用<script setup>来大幅度地简化代码。 -
备注:什么是单文件组件
- 在 Vue 应用中,提供了
.vue为后缀的文件,我们将这类的文件,称之为“单文件组件”,也就是说,每一个文件,都是一个单独的组件。(其实我们平时每个.vue文件都是单文件组件)
- 在 Vue 应用中,提供了
-
单文件组件写法
-
<template> <div> <div>{{ state.count }}</div> <button @click="addCount">点击count累加</button> </div> </template> <script setup> import { reactive } from 'vue'; // 利用reactive设置响应式数据 const state = reactive({ count: 0 }) // 使count++的函数 function addCount() { state.count++ } </script> <style scoped lang='less'> </style>
3、reactive()的局限性
- 仅对对象类型有效(对象、数组和 Map、Set这样的集合类型),而对
string、number和boolean这样的 原始类型无效。 - 因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失:
-
<template> <div> <div>{{ state.count }}</div> <button @click="countValue(count)">点击触发函数</button> </div> </template> <script setup> import { reactive } from "vue"; /** * 因为 Vue 的响应式系统是通过属性访问进行追踪的, * 因此我们必须始终保持对该响应式对象的相同引用。 * 这意味着我们不可以随意地“替换”一个响应式对象, * 因为这将导致对初始引用的响应性连接丢失: */ // let state = reactive({ count: 0 }) // state = reactive({ count: 1 }) let state = reactive({ count: 0 }) // 此处的n不是响应式的 let n = state.count n++ // count也不是响应式的 let { count } = state count++ function countValue(count) { const a = state.count++ console.log('解构后的count,失去了响应式', count) console.log('响应式count', a) } </script>
4、ref()
- 允许创建可以使用任何值类型的响应式 ref
-
<template> <div> <!-- 模板中使用不需要加value --> <div>ref定义响应式(简单): {{ count }}</div> <div>ref定义响应式(复杂):{{ countObj }}</div> <button @click="addCount">+1</button> </div> </template> <script setup> import { ref } from "vue"; // 简单数据类型设置响应式 let count = ref(100) let countObj = ref({ count: 1 }) let obj = { foo: ref(1) } // foo是解构出来的,但也是响应式的 const { foo } = obj function addCount() { count.value++ countObj.value.count++ obj.foo.value++ console.log(countObj.value, foo.value) } </script> <style scoped lang='less'> </style>
5、响应性语法糖(待总结)
计算属性
- computed()`方法期望接收一个 getter 函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,你可以通过 publishedBooksMessage.value访问计算结果。
- 计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value
-
<template> <div> <p>Has published books:</p> <!-- 不使用计算属性时 --> <div>{{ author.books.length > 0 ? 'Yes' : 'No' }}</div> <!-- 使用计算属性时 --> <div>{{ publishedBooksMessage }}</div> <button @click="changeComputed">尝试修改计算属性</button> <!-- 可修改的计算属性 --> <div>你的名字是: {{ fullName }}</div> </div> </template> <script setup> import { computed, reactive, ref } from 'vue' const author = reactive({ name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] }) // 计算属性 let publishedBooksMessage = computed(() => { return author.books.length > 0 ? 'Yes' : 'No' }) const firstName = ref('John') const lastName = ref('Doe') const fullName = computed({ // getter get() { return firstName.value + ' ' + lastName.value }, // setter set(newValue) { // 注意:我们这里使用的是解构赋值语法 [firstName.value, lastName.value] = newValue.split(' ') } }) const changeComputed = () => { fullName.value = 'Xiao Fu' } </script> <style scoped lang='less'> </style>
1、计算属性和方法的区别
- 不考虑其他东西,两者可实现相同的效果,都可以去依赖其他项去计算
- 区别在于计算属性值会基于其响应式依赖被缓存,计算属性仅会在其响应式依赖更新时才会重新计算,依赖项不变,计算属性也不会发生变化,不会去重复执行getter函数
- 而方法总是会在重新渲染时再次执行函数,不管依赖项有没有发生改变
- 函数形式的计算属性是只读的,当你尝试修改一个计算属性时,你会收到一个运行时警告(官网解释,但自己试了一下没有警告,但模板渲染的值没有进行更新)
- 计算属性设置为对象形式时,会有get和set方法,set方法可以对计算属性进行修改,对象形式的计算属性是可读可写的,修改之后如果模板用到这个计算属性时,也会发生相应的更新
2、总结
- 官方建议计算属性是基于原有数据的一个派生,依赖于其他值进行变化,其他值发生变化计算属性才会跟着变化,计算属性应该是只读的,不要去直接更改它,更建议通过依赖项的改变去触发它的重新计算。
类与样式绑定
-
<template> <div> <!-- 字面量方式绑定 --> <div :class="{ active: isActive }"> 1111 </div> <!-- 对象方式绑定 --> <div :class="classObject">222</div> <!-- 数组形式绑定 --> <div :class="[activeClass, errorClass]">333</div> </div> </template> <script setup> import { reactive, ref } from 'vue' const isActive = ref(true) // 对象方式直接绑定 const classObject = reactive({ active: true, 'text-danger': true }) const activeClass = ref('active') const errorClass = ref('text-danger') </script> <style scoped> .active { margin: 10px; width: 100px; height: 100px; background-color: orange; } .text-danger { font-size: 30px; } </style>
条件渲染
v-if和v-show
-
和vue2一致
-
两者都能控制dom元素的显隐,区别在于
- v-if实现元素显隐的原理是DOM的创建销毁,会经历组件的创建和销毁
- v-show实现元素显隐的原理是进行样式的控制,通过操控display: none / block进行控制,无论元素是否显示,它都会进行渲染,在显隐切换的过程中不会经历组件的创建和销毁
- 因此来说,v-if有更高的切换开销,v-show有更高的渲染开销,当频繁进行切换时,v-show相对较好,当绑定条件很少改变时,v-if相对更加合适
-
和vue2的区别
-
v-if和v-for同时使用时,v-if的优先级更高
- 也就意味着v-if的条件无法访问到v-for作用域内定义的变量别名
-
不建议两个出现在一起,造成性能的浪费
-
列表渲染
v-for
-
和vue2基本一致
-
小妙招
- 假设有一个数组,数组每一项是数组,如果想要遍历小数组的每一项该怎么弄
- 可以先遍历大数组,v-for的item就是每一个小数组,再遍历item,item的每一项就是小数组的每一项
-
<ul v-for="numbers in sets"> <li v-for="n in even(numbers)">{{ n }}</li> </ul> <script> const sets = ref([ [1, 2, 3, 4, 5], [6, 7, 8, 9, 10] ]) function even(numbers) { return numbers.filter((number) => number % 2 === 0) } </script>
事件处理
-
v-on:事件类型 / @事件类型进行触发事件执行相应的方法逻辑
-
可以跟一个方法,也可以编写内联JavaScript代码
-
方法没有参数时可以只写方法名,当有参数时可以(参数)进行传参处理
-
需要访问原生dom事件时,可以传入一个特殊的$event, 或者使用内联箭头函数
-
<template> <div> <!-- 使用特殊的 $event 变量 --> <button @click="warn('Form cannot be submitted yet.', $event)"> Submit </button> <!-- 使用内联箭头函数 --> <button @click="(event) => warn('Form cannot be submitted yet.', event)"> Submit </button> </div> </template> <script setup> function warn(a, e) { console.log(a, e); } </script>暂时未写功能描述
-
事件修饰符
.stop.prevent.self.capture.once.passive
-
按键修饰符
.enter.tab.delete(捕获“Delete”和“Backspace”两个按键).esc.space.up.down.left.right
-
系统按键修饰符
-
.ctrl -
.alt -
.shift -
.meta- 当出现链式使用时,例如@keyup.ctrl.alt,它会再ctrl + alt 键弹起时触发
-
.exact:使用系统按键修饰符不跟.exact时,指定按键触发时同时按下别的键也会触发,但加上.exact后就不会触发,有且只能指定按键触发,多一个都不行
-
-
鼠标按键修饰符
.left.right.middle