「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」。
关于3.0版本配置和cil升级就不过多赘述了,下面只介绍常用的api及使用方式
defineComponent
defineComponent函数,只是对setup函数进行封装,返回options的对象,defineComponent最重要的是:在TypeScript下,给予了组件 正确的参数类型推断 。
import { defineComponent, ref } from 'vue'
const HelloWorld = defineComponent(function HelloWorld() {
const count = ref(0)
return { count }
})
setup
setup函数为vue3.0的composition API提供了统一的入口
通过steup函数的第一个形参,接收props数据
第二个形参是一个对象,这个对象在2.0中需要通过this才能访问,在vue3中用content. 访问
<script>
export default defineComponent({
setup (props, content) {
props: {
msg: '子组件传递'
}
content.emit
content.refs
}
})
</script>
对比2.x省去了options声明的data(){ }
<div>{{data}}</div>
<script>
// 1. 从 vue 中引入 ref 函数
import { ref } from 'vue'
export default ({
setup(){
// 2.定义一个单值,响应式变量
const data = ref('这是一个标题')
// 3.访问变量需要.value
console.log(data.value)
// 4.返回出去
return {
data
}
}
})
</script>
reactive
reactive函数用来返回一一个响应式对象,示例如下:
<template>
<div id="app">
<!-- 4. 访问响应式数据对象中的 count -->
{{ count }}
</div>
</template>
<script>
// 1. 从 vue 中导入 reactive
import {reactive} from 'vue'
export default {
name: 'App',
setup() {
// 2. 创建响应式的数据对象
const data = reactive({count: 3})
// 3. return 出去,供template使用
return { data }
}
}
</script>
ref
关于和reactive的区别,ref定义的数据,打印的结果是一个被对象包裹的响应式数据,但是如果reactive去定义一个单值,浏览器会报黄错,提示值不能被reactive创建
所以,简易在初始定义数据时,reactive定义复杂的数据类型,ref定义基本数据类型, 如果非要使用reactive,需要把值包裹一下,如:const data = reactive({ val: 10 }), ref定义的数据访问的时候需要加 .value,reactive不需要,使用ref定义基本数据类型,也可以定义数据和对象
示例如下:
<template>
<div id="app">
{{ data.count }}
</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
name: 'App',
setup() {
const data = ref(0)
const data = { count: 3 }
return reactive({
data
})
}
}
</script>
toRef
toRef是将某个对象中的某个值转化为响应式对象,并接收两个参数,第一个是对象,第二个是对象的属性名
<script>
// 1. 导入 toRef
import {toRef} from 'vue'
export default {
setup() {
const obj = {count: 3}
// 2. 将 obj 对象中属性count的值转化为响应式数据
const state = toRef(obj, 'count')
// 3. 将toRef包装过的数据对象返回供template使用
return {state}
}
}
</script>
toRefs
<template>
<div>
{{ name }}
</div>
</template>
<script>
// 1. 导入 toRefs
import { toRefs } from 'vue'
export default {
setup() {
const obj = {
name: '测试',
age: 22,
gender: 0
}
// 2. 将 obj 对象中属性count的值转化为响应式数据并返回
return {
...toRefs(obj)
}
}
}
</script>
ref和toRef的区别:
| 1 | ref本质是拷贝,修改响应式数据不会影响原始数据;toRef的本质是引用关系,修改响应式数据会影响原始数据 |
|---|---|
| 2 | ref数据发生改变,界面会自动更新;toRef当数据发生改变是,界面不会自动更新 |
| 3 | toRef传参与ref不同;toRef接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性 |
watch
示例如下:
监听ref()
<script>
// 1. 导入watch
import { watch } from 'vue'
export default {
setup() {
const data = ref(0)
watch(data, (newval, oldval) => ) {
console.log(newval)
console.log(oldval)
}
// 1秒后data + 1
setTimeout(() => {
data.value ++
}, 1000)
return {
data
}
}
}
</script>
监听reactive()
<script>
// 1. 导入watch
import { watch } from 'vue'
export default {
setup() {
const data = reactive({
count: 0
})
watch(() => data.count, (newval, oldval) => {
console.log(newval)
console.log(oldval)
})
// 1秒后data + 1
setTimeout(() => {
data.count ++
}, 1000)
return {
data
}
}
}
</script>
监听多个值
<script>
// 1. 导入watch
import { watch } from 'vue'
export default {
setup() {
const data = reactive({
count: 0,
name: 'cs'
})
watch(
[() => data.count, () => data.name],
([newcount, newname], [oldcount, oldname]) => {
console.log(newcount) // 新的count值
console.log(newname) // 新的name值
console.log(oldcount) // 旧的name值
console.log(oldname) // 旧的name值
}
)
// 1秒后data + 1
setTimeout(() => {
data.count ++
data.name = 'xx'
}, 1000)
return {
data
}
}
}
</script>
computed
<script>
import { ref, computed } form 'vue';
export default {
setup () {
// computed 计算属性使用
const age = ref(18) // age 现在就是响应式对象
// computed 计算属性是一个函数 传入一个函数getter
const nextAge = computed(()=> {
return parseInt(age.value) + 1
})
// 返回的是一个不可以修改的计算属性
return {
age,
nextAge
}
}
}
</script>
Vue2.x与Vue3.x的生命周期
| Vue2 | Vue3 | |
|---|---|---|
| beforeCreate | setup | |
| created | setup | |
| beforeMount | onBeforeMount | 在挂载前执行某些代码 |
| mounted | onMounted | 在挂载后执行某些代码 |
| beforeUpdate | onBeforeUpdate | 在更新前前执行某些代码 |
| updated | onUpdated | 在更新后执行某些代码 |
| beforeDestory | onBeforeUnmount | 在组件销毁前执行某些代码 |
| destoryed | onUnmounted | 在组件销毁后执行某些代码 |
在setup中调用
<script>
// 1. 从 vue 中引入 多个生命周期函数
import {onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
unMounted} from 'vue'
</script>
Vue3.x使用工具函数
因为弃用了之前过滤器的写法,所有的函数方法都必须return出去
如转换时间:
import { timeFormat } from '@/utils/index'
return {
timeFormat
}
<div class="time">{{timeFormat(item.time)}}</div>
vue2.x的话就是在methods里面声明一下也可以
methods: {
timeFormat
}
Vue3.x中的vuex
main.js中的导入
import store from './store/index'
const app = createApp(store)
// 将store实例作为插件安装
app.use(store)
state
因为vuex使用的是单一状态树,用一个对象就包含了所有层级状态
获取state状态:
方法一:通过ref返回一个响应式数据
方法二:通过计算属性返回 computed(() => store.state.count).value)
方法三:mapstate函数展开获取
getter
相当于computed 计算属性
index.js
import { createStore } from 'vuex'
const store = createStore({
state: {
return {
userLsit: [
{ id: 1, name: '张' },
{ id: 2, name: '李' }
]
}
},
getter: {
// 获取id的函数
getId: (state) => (id) => {
let user = state.userList.find(e => e.id === id)
if (user) {
return user.name
}
},
// 获取列表
getName: (state) => {
return state.userList
}
}
})
index.vue
<template>
<div>
<div @click="getUser">获取用户</div>
<div>id为1的用户是: {{ userName }}</div>
</div>
</template>
<script>
import { useStore } from "vuex"
import { ref } from "vue"
export default {
setup () {
// 获取store实例
let store = useStore()
// 定义值
let userName = ref("")
// 返回state内的值
let getUser = () => {
userName.value = store.getters.getId(1)
console.log(userName.value) // { id: 1, name: '张' }
console.log("用户列表:", store.getters.getName)
},
return {
getUser,
userName
}
}
}
</script>
mutation(同步函数)
mutation相当于定义一个事件,store.commit('事件名',value)外面触发事件
index.js
import { createStore } from 'vuex'
//创建一个新的store实例
const store = createStore({
//存储数据
state() {
return {
count: 0
}
},
//修改数据的方法
mutations: {
add(state, value: number) {
state.count += value
}
}
})
export default store;
在组件中使用
<template>
<div>
<span>{{ data }}</span>
<button @click="change">修改值</button>
</div>
</template>
<script>
import { ref } from 'vue'
import { useStore } from "vuex"
export default {
//获取store实例
const store = useStore();
// 默认值
const data = ref(0)
// 修改值
const change = () => {
store.commit('add', 1)
}
// 获取值
data.value = store.state.count
return {
data,
change
}
}
</script>
Action
Action类似于mutation,不同在于:
action提交的是mutation,而不是直接变更状态
action可以包含任意异步操作
const store = createStore({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
Vue-router4
router下index.js
import { createRouter, createWebHashHistory } from 'vue-router'
// 工厂函数创建router实例
const router = createRouter({
history: createWebHashHistory(),
routes: [
{ path: '/home' component: () => import('views/index.vue') }
]
})
export default router
组件中使用和传参等操作
<template>
<div>
<router-link to="/home">Home</router-link>
<div @clikc="go">跳转路由传参</div>
</div>
<router-view></router-view>
</template>
<script>
// this.$router 或 this.$route没了,作为替代,我们使用 useRouter 函数:
// 如果有参数的话,还要导入useRoute Api
import { useRouter, useRoute } from "vue-router"
import { reactive, watch } from "vue"
export default {
setup() {
const state = reactive({
id: route.query.id, // query
id: route.params.id // params
})
// 定义router变量
const router = useRouter()
const route = useRoute()
// 跳转方法
const go = () => {
// router.push跳转页面
// 命名的路由 params传参 变成 /index/123
route.push({ name: 'user', params: { id: '123' }})
// 带查询参数,query传参 变成 /index?userId=123
router.push({ path: 'index', query: { id: '123' }})
}
// 当前页面监听router变化, 监听params参数的变化
watch(() => route.params, () => {
// 执行操作
})
return {}
}
}
</script>
router自带的tab切换class
<template>
<div>
<div class="nav">
<router-view></router-view>
<router-link class="nav-item" to="/add">nav1</router-link>
<router-link class="nav-item" to="/done">nav2</router-link>
<router-link class="nav-item" to="/delete">nav3</router-link>
</div>
</div>
</template>
<style>
.active {
font-weight: bolder;
color: #000;
}
</style>
router.js
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Index',
component: () => import('../views/Index.vue'),
children: [
{
path: '',
redirect: { name: 'add' }
},
{
path: '/add',
name: 'add',
component: () => import('../components/Add.vue')
},
{
path: '/done',
name: 'done',
component: () => import('../components/Done.vue')
},
{
path: '/delete',
name: 'delete',
component: () => import('../components/Delete.vue')
},
]
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
linkActiveClass: 'active' ////设置 链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 linkActiveClass 来全局配置
})
export default router