Vue 3 是 Vue 当前的最新主版本。它包含了一些 Vue 2 中没有的新特性 (比如 Teleport、Suspense,以及多根元素模板)。同时它也包含了一些与 Vue 2 非兼容性的变更
简单概念
- 什么是Vue,什么是单文件组件
Vue是基于 HTML、CSS 和 JS 的一套声明式的、组件化的 JavaScript 框架;Vue把 HTML、CSS 和 JS封装在同一个Vue文件里,通过解析模板去进行解析,再通过预处理器去处理。它给我们带来了模板化开发,独立作用域,预处理器等多种优点。
- 什么是模板语法
Vue 使用一种基于 HTML 的模板语法,能够声明式地将数据绑定到 DOM 上。通过解析器进行解析
<span>文本插值 {{ msg }}</span>
<span :text="text">属性绑定attar</span>
<span :[attar]="text">动态参数attar</span>
<span @[attar]="text">动态方法attar</span>
简单使用
vue目前有两种编写方式,你可以使用vue2版本的选项式编写,也可用使用vue3新添加setup函数,文章后面的示例大部分用了setup组合式语法
//选项式
export default {
data() { //data数据
return{
count:1,
}
},
mounted() { //生命周期钩子
console.log(this.count) // 1
},
}
<script setup>
//组合式
import { ref,onMounted } from 'vue'
const count = ref(0) //data数据
onMounted(()=>{ //生命周期钩子
console.log(count.value) // 1
})
</script>
响应式数据 ref reactive
ref
和 reactive
是vue3基于组合式api模式下,在 setup
中用于声明的具有响应式的数据的方法, ref
通常用于声明基础类型响应式数据,reactive
用于声明复杂类型响应式数据
import { ref, reactive } from 'vue'
const count = ref(1)
console.log(count.value) // 1
const state = reactive({ count:1 })
console.log(state.count) // 1
计算属性 computed
接受一个 getter
函数,返回一个只读的响应式 ref
对象。该 ref
通过 .value
暴露 getter
函数的返回值。它也可以接受一个带有 get
和 set
函数的对象来创建一个可写的 ref 对象
import { reactive, computed } from 'vue'
const state = reactive({
name: 'John Doe',
})
const publish = computed(() => { // 只读,赋值会错误
return state.name == 'John Doe' ? 'Yes' : 'No'
})
//高级:可编辑计算属性
const fullName = computed({
get() { //getter
return firstName.value + ' ' + lastName.value
},
set(newValue) { //setter
[firstName.value, lastName.value] = newValue.split(' ')
}
})
样式属性 :class :style
vue可以通过响应式ref
reactive
对象给元素对象动态绑定class和属性
import {ref,reactive} from 'vue'
const isActive = ref(true)
const classObject = reactive({
active: true
})
const styleObject = reactive({
color: 'red',
fontSize: '13px'
})
<div :class="{ active: isActive }"></div>
<div :class="classObject"></div>
<div :style="styleObject"></div>
指令·修饰符 v-text
v-once
仅渲染一次v-text
更新元素的文本内容v-html
更新元素的 innerHTMLv-pre
跳过该元素及其所有子元素的编译v-cloak
用于隐藏尚未完成编译的 DOM 模板<span v-once v-text="msg"></span> <span v-cloak v-html="innerhtml"></span> <span v-pre>{{masg}}</span>
v-show
基于表达式值的真假性,来改变元素的display
来改变可见性v-if
基于表达式值的真假性,来改变元素的是否渲染来改变可见性v-else-if
基于v-if
的链式表达v-else
基于v-if
或v-else-if
的链式表达<span v-show="msg=='na'"></span> <span v-if="msg=='na'"></span> <span v-else-if="msg=='ma'"></span> <span v-else></span>
v-for
基于原始数据多次渲染元素或模板块v-memo
基于依赖数组进行优化<div v-for="item in items" :key="item.key" v-memo="items"> {{ item.text }} </div>
v-on
给元素绑定事件监听器,缩写符@
<span v-on:click="msg='na'">{{mag}}</span> <span @click.stop="msg='na'">{{mag}}</span> <!-- .stop ---- 调用 event.stopPropagation() --> <!-- .prevent - 调用 event.preventDefault() --> <!-- .capture - 在捕获模式添加事件监听器 --> <!-- .self ---- 只有事件从元素本身发出才触发处理函数 --> <!-- .{keyAlias} - 只在某些按键下触发处理函数 --> <!-- .once ---- 最多触发一次处理函数 --> <!-- .left ---- 只在鼠标左键事件触发处理函数 --> <!-- .right --- 只在鼠标右键事件触发处理函数 --> <!-- .middle -- 只在鼠标中键事件触发处理函数 --> <!-- .passive - 通过 { passive: true } 附加一个 DOM 事件 -->
v-bind
给元素绑定事件监听器,缩写符:
<span v-bind:title="msg"></span> <!-- .camel - 将短横线命名的 attribute 转变为驼峰式命名 --> <!-- .prop -- 强制绑定为 DOM property (3.2+) --> <!-- .attr -- 强制绑定为 DOM attribute (3.2+) -->
v-model
在表单输入元素或组件上创建双向绑定<input v-model="msg"/> <!-- .lazy - 监听 change 事件而不是 input --> <!-- .number - 将输入的合法字符串转为数字 --> <!-- .trim - 移除输入内容两端空格 -->
自定义指令
指令比 autofocus attribute 更有用,因为它不仅仅可以在页面加载完成后生效,还可以在 Vue 动态插入元素后生效
<script setup>
// 在模板中启用 v-focus; 以v开头的驼峰式命名的变量都可以被用作一个自定义指令
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
//全局注册
const app = createApp({})
// 使 v-focus 在所有组件中都可用
app.directive('focus', {
/* ... */
})
生命周期 Mount
选项式代码则和Vue2相同,组合式代码和选项式相比,少了 beforeCreate 和 created
onBeforeMount() //在组件挂载之前调用
onMounted() //在组件挂载完成后执行
onBeforeUpdate() //在组件更新之前执行
onUpdated() //在组件更新完成后执行
onBeforeUnmount()//在实例卸载之前执行
onUnmounted() //在实例卸载完成后执行
onActivated() //缓存组件插入时触发
onDeactivated() //缓存组件移除时触发
onErrorCaptured() //子组件发生错误时执行
//(仅开发可用)
onRenderTracked() //当组件渲染过程中追踪到响应式依赖时调用
onRenderTriggered() //当组件渲染过程中追踪到响应式依赖时调用
//(仅SSR可用)
onServerPrefetch() //在组件实例在服务器上被渲染之前调用
侦听器 watch
直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器
import { ref, watch,watchEffect } from 'vue'
const question = ref('')
// 监听question的变化
watch(question, async (new, old) => {
console.log(new, old)
}
// 加入 immediate 会立即执行一遍
// ,{ immediate: true }
)
watchEffect(async () => {
const response = await fetch(
`https://xxx/todos/${todoId.value}`
)
data.value = await response.json()
})
依赖注入 provide
//祖父组件
import {ref,provide} from 'vue'
//提供监听值
const testValue = ref(1)
provide('testKey',testValue)
setTimeOut(()=>{
testValue.value = 2
})
import {inject} from 'vue'
//监听值
inject('testKey',(value)=>{
console.log(value)
})
组件注册
全局引用
import { createApp } from 'vue'
const app = createApp({})
app.component(
// 注册的名字
'MyComponent',
// 组件的实现
{
/* ... */
}
)
而在setup中,引入则无需注册
<script setup>
import ComponentA from './ComponentA.vue'
</script>
<template>
<ComponentA />
</template>
内置组件
- Transition 内置动画,通过v-if进行设置
<Transition>
<p v-if="show">hello</p>
</Transition>
<style>
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>
- TransitionGroup 是一个内置组件,用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item">
{{ item }}
</li>
</TransitionGroup>
<style>
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>
- KeepAlive 在多个组件间动态切换时缓存被移除的组件实例
<!-- 非活跃的组件将会被缓存! -->
<KeepAlive>
<component :is="activeComponent" />
</KeepAlive>
组件传值
props
const props = defineProps(['foo'])
console.log(props.foo)
// 或者
defineProps({
title: String,
likes: Number
})
$emit
const emit = defineEmits({
// 没有校验
click: null,
// 校验 submit 事件
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
问题
ref 和 reactive 的区别
reactive:(1)它的响应式是更加‘深层次’的,底层本质是将传入的数据包装成一个Proxy。(2)参数必须是对象或者数组,如果要让对象的某个元素实现响应式时比较麻烦。需要使用toRefs (3)更适合复杂对象
ref:(1)函数参数可以是基本数据类型,也可以接受对象类型。(2)如果参数是对象类型时,其实底层的本质还是reactive,系统会自动根据我们给ref传入的值转换成(3)更适合简单类型