1、简介
vue是一款用于构建用户界面的javascript框架。它基于标准的HTML、CSS和Javascript构建,并提供了一套声明式的、组件化的编程模型,帮助高效的开发用户界面。
2、基础知识
2.1 创建应用
import { createApp } from 'vue'
// 从一个单文件组件中导入根组件
import App from './App.vue'
const app = createApp(App)
2.2 模板语法
插值文本
使用{{ msg }}
直接进行展示。
插入html
使用v-html指令渲染富文本:<span v-html="rawHtml"></span>
属性绑定
<div :id="idValue"></div>
将div的id属性与idValue进行绑定,如果idValue为null或者undefined时,则不会显示id属性。完整写法为v-bind:id,实际使用中,v-bind可以直接可以省略掉;
动态绑定多个属性
可以通过不带参数的v-bind将多个属性同时绑定到元素上,如:
const objectOfAttrs = {
id: 'container',
class: 'wrapper'
}
<div v-bind="objectOfAttrs"></div>
使用javascript表达式
vue中所有的数据绑定都支持javascript表达式,并且仅支持单一表达式,不支持语句和逻辑控制等,如:
{{ count + 1 }}
{{ isTrue ? 1 : 0 }}
{{ message.split(',') }}
<div :id="`list-${index}`"></div>
{{ format(date) }}:如果使用方法进行渲染,此时组件在每次更新时都会被重新调用,因此不能做任何改变数据或者触发异步操作
指令
指令指的是带有 v-
前缀的特殊属性,如前面的v-html、v-bind;指令的参数:
<a v-bind:href="href"></a>:设置指令的参数为href
<a v-bind:[attributeName]="href"></a>:指令也可以设置动态参数,只需要将参数名用[]括起来,即表示动态参数;动态参数名应该是一个字符串或者null,不应该使用表达式;如果是复杂的动态参数,可以使用计算属性来解决;
修饰符
修饰符是以点开头的特殊后缀,表名指令需要以一些特殊的方式被绑定。
.prevent: <form @submit.prevent="onSubmit"></form>
,告知指令对触发的事件调用event.preventDefault();
2.3 响应式声明
ref()
使用ref()来声明响应式状对象,然后可以使用.value属性来返回对象的值。需要注意的是,在模板中使用ref对象时,会自动解包,不需要添加.value,直接使用即可。{{ count }}
<template>
{{ count }}
</template>
<script setup>
import { ref } from 'vue'
// 声明count为响应式对象
const count = ref(0);
// 操作响应式对象
count.value ++;
</script>
在ts中,为ref标注类型:
<script setup>
import { ref, type Ref } from 'vue'
const year: Ref<number> = ref(2020)
</script>
为什么要使用带有.value属性的ref,而不是普通的变量?
在vue中,ref值改变的时候,需要相应的更新对应的DOM,在标准的javascript中,检测普通变量的访问和修改是行不通的,而使用.value形式的对象时,可以通过setter和getter方法来拦截对象属性的set和get操作,从而来触发DOM的更新(这里需要注意的是:ref改变后,DOM的更新不是同步的,而是会在next tick更新周期中缓冲所有状态的修改,以确保不管修改多少次状态,每个组件只会被更新一次。因此,如果想要等待DOM更新完成后,执行相应的代码,可以使用nextTick()方法)。另一方面,因为ref是对象,当传递给函数时,可以保留对最新值的访问。
reactive()
ref()是创建一个具有.value属性的响应式对象,而reactive()是使对象本身具有响应性(因此,reactive只能用于对象类型,不能用于如string、number或boolean这样的原始类型)。需要注意的是,reactive()返回的是原始对象的Proxy,它和原始对象是不相同的。
<template>
{{ proxy.count }}
</template>
<script setup lang="ts">
import { reactive } from 'vue'
const raw = { count: 0 }
const proxy= reactive(raw)
console.log(proxy=== raw); // false
// 在同一个对象上调用 reactive() 会返回相同的代理
console.log(reactive(raw) === proxy) // true
// 在一个代理上调用 reactive() 会返回它自己
console.log(reactive(proxy) === proxy) // true
</script>
建议使用ref()作为响应式状态的主要API。
2.4 计算属性
在模板中,可以使用javascript表达式,但是如果模板中的逻辑过于复杂,维护起来就会很难,因此,如果需要在模板中显示复杂逻辑,可以使用计算属性。
<template>
{{ showMsg }}
</template>
<script setup lang="ts">
import { computed } from 'vue';
const count = ref(0);
// 返回计算属性 ref对象
const showMsg = computed<number>(() => {
return count.value + 1;
})
</script>
需要注意的是,计算属性的值会基于其响应式依赖被缓存,如上面例子,只有当count发生变化的时候,showMsg才会重新进行计算,这也是计算属性和方法的主要区别。
其次,默认情况下,计算属性是只读的,不能被修改。如果需要计算属性可写,需要提供set和get方法,这个意义不大,计算属性的返回值应该被视为只读的,并且永远不应该被更改。
2.5 class和style的绑定
<template>
<!-- 对象方式 -->
<div :class="{active: isActive}"></div>
<!-- 数组方式 -->
<div :class="['class1', isActive ? 'active' : '']"></div>
<!-- 嵌套对象方式 -->
<div :class="['class1', {active: isActive}]"></div>
<!-- 计算返回 -->
<div :class="classObject"></div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const isActive = ref(true);
// 使用computed计算得出也是一样的
const classObject = reactive({
active: true,
'text-danger': false
})
<script>
style的绑定和class绑定基本一致,只是将绑定对象换成:style,其他逻辑不变。
2.6 条件渲染
通过v-if
、v-else-if
、v-else
、v-show
来有条件的渲染一块内容,只有当返回值为真时,内容才会被渲染出来。
<template>
<div v-if="user.name == 'a'">姓名</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const user = ref({
name: 'a'
});
</script>
v-if和v-show的区别:
v-if的渲染是真实的,只有为true时,才会渲染;而v-show,无论结果如何,都会渲染,只是display属性会进行切换。因此,v-if拥有更高的切换开销,如果运行时,绑定条件很少改变,则v-if更适合;v-show有更高的初始渲染开销,如果需要频繁切换,则v-show效果更好。
2.7 列表渲染
可以通过v-for指令来渲染一个数组列表,指令内使用item in array
形式的语法,其中,array是需要显示的数组,item是数据每一项的别名。
<template>
<div v-for="item in array" :key="item.id">
{{ item }}
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const array = ref([{id: 1, name: '张三'}, {id: 2, name: '李四'}]);
</script>
使用v-for遍历对象属性,遍历出来的属性是基于对象Object.keys()返回值来决定:
<template>
<!-- 这里的value是对象的值 -->
<div v-for="value in array" :key="value">
{{ value }}
</div>
<!--
通过多参的形式,来获取不同的属性
第一个参数:对象的属性值
第二个参数:对象的key
第三个参数:位置索引
-->
<div v-for="(value, key, index) in array" :key="value">
{{ value }}
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const array = ref({id: 1, name: '张三'});
</script>
注意:
(1)v-for每个元素对应的块,必须提供一个唯一的key属性,以方便vue跟踪每个节点的标识,从而重用和重新排序现有的元素;
(2)同一个dom节点上,别同时使用v-for和v-if,v-if的优先级会比v-for高,也就是说v-if的条件无法使用v-for作用域内定义的变量;
(3)在使用数组时,vue只能通过push、pop、shift、unshift、splice、sort、reverse这些方法监听到数组的变化,从而触发相关的更新。
2.8 事件处理
可以通过 v-on
指令(简写 @
)来监听dom事件,并在事件触发时执行对应的方法。
<template>
<!-- 内联事件处理器,直接写相关语法 -->
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>
<!-- 方法事件处理器,调用相关方法 -->
<button @click="add">Add 1</button>
<!-- 自定义传参 -->
<button @click="say('你好')">自定义传参</button>
<!-- 自定义传参,并传入事件对象 -->
<button @click="sayEvent('你好', $event)">自定义传参</button>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const count = ref(0);
const add = (event: MouseEvent) => {
count.value ++;
}
const say = (word: string) => {
console.log(word);
}
const sayEvent = (word: string, event: MouseEvent) => {
console.log(word);
}
</script>
事件修饰符
<template>
<!-- 单击事件将停止传递 -->
<button @click.stop="dosomething">自定义传参</button>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="dosomething"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="dosomething"></a>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="dosomething">...</div>
<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="dosomething">...</div>
<!-- 点击事件最多被触发一次 -->
<a @click.once="dosomething"></a>
<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 , 一般用于触摸事件的监听器,可以用来改善移动端设备的滚屏性能。-->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="dosomething">...</div>
<!--
监听键盘事件,仅在 `key` 为 `Enter` 时调用 `submit`
vue中常用的按键别名:
- .enter
- .tab
- .delete (捕获“Delete”和“Backspace”两个按键)
- .esc
- .space
- .up
- .down
- .left
- .right
-->
<input @keyup.enter="dosomething" />
<!-- 监听键盘事件,可以直接使用 KeyboardEvent.key 暴露的按键名称作为修饰符,但需要转为 kebab-case 形式 -->
<input @keyup.page-down="dosomething" />
<!--
系统按键修饰符,
- .ctrl
- .alt
- .shift
- .meta:在 Mac 键盘上,meta 是 Command 键 (⌘)。在 Windows 键盘上,meta 键是 Windows 键 (⊞)。在 Sun 微机系统键盘上,meta 是钻石键
- .exact:控制触发一个事件所需的确定组合的系统按键修饰符
-->
<!-- Alt + Enter -->
<input @keyup.alt.enter="dosomething" />
<!-- Ctrl + 点击 -->
<div @click.ctrl="dosomething">Do something</div>
<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="dosomething">A</button>
<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="dosomething">A</button>
<!--
鼠标按键修饰符
.left
.right
.middle
这些修饰符将处理程序限定为由特定鼠标按键触发的事件。
-->
</template>
<script setup lang="ts">
import { ref } from 'vue';
const dosomething = () => {}
</script>
2.9 输入绑定
使用v-model来进行表单数据的绑定。
<template>
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edit me" />
<!-- .lazy修饰符,在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="message" />
<!-- 让用户输入自动转换为数字,如果该值无法被 parseFloat() 处理,那么将返回原始值 -->
<input v-model.number="age" />
<!-- 默认自动去除用户输入内容中两端的空格 -->
<input v-model.trim="message" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const message = ref()
const age = ref()
</script>
Comments NOTHING