前言:
vue3项目是在两年前开始的,正式版3.0于2020年9月发布;
目前vue生态支持情况还不完善,如vuex4还处于rc版本,并存在一定的bug,暂不推荐大家用在标准版项目里;
不过那些无关紧要的项目必须可以试试;
再者vue3的官方生态包为了让打包后的文件尽可能的小,打包文件都输出了ECMASCRIPT新语法,这就是网上吹牛逼说的vue3更快、更小;
一、生命周期
- beforeCreate -> setup()
- created -> setup()
- beforeMount -> onBeforeMount // 在挂载前执行某些代码
- mounted -> onMounted // 在挂载后执行某些代码
- beforeUpdate -> onBeforeUpdate // 在更新前前执行某些代码
- updated -> onUpdated // 在更新后执行某些代码
- beforeDestroy -> onBeforeUnmount // 在组件销毁前执行某些代码
- destroyed -> onUnmounted // 在组件销毁后执行某些代码
- errorCaptured -> onErrorCaptured // 错误捕获
二、常用api
!中文文档(https://www.vue3js.cn/docs/zh/api/global-api.html#createapp)
- ref
- reactive
- watch
- computed
- nextTick
- props
三、vite创建vue3项目
文档地址(https://vitejs.dev/guide/#scaffolding-your-first-vite-project)
- npm init @vitejs/app my-vue-app --template vue
- cd .\my-vue-app\
- npm install
-
ref演示
<template>
<button @click="state++">count is: {{ state }}</button>
</template>
<script setup>
import { ref } from 'vue'
const state = ref(0)
</script>
- 提示:获取dom也需要ref
- 思考1:怎么用ref获取dom
-
reactive演示
<template>
<button @click="state.count++">count is: {{ state.count }}</button>
</template>
<script setup>
import { reactive } from 'vue'
const state = reactive({ count: 0 })
</script>
- 思考2:以上可以看出,如果用reactive声明n个变量,在dom中使用都要加上state.xxx,岂不是很麻烦,
现在我要这样的效果 <div>count is: {{ count }}</div>,您会怎么做?
-
watch演示
<template>
<div>reactive</div>
<button @click="state.count ++">count is: {{ state.count }}</button>
<div>{{ state.text }}</div>
</template>
<script setup>
import { reactive, watch } from 'vue'
const state = reactive({
count: 0,
text: 'ready'
})
watch(() => state.count, (n, o) => {
if (n > 5) state.text = '大哥,别点了,count大于5了';
else state.text = 'count小于5';
});
</script>
- 思考3:
- 我想同时监听多个变量,该怎么做
- 深度监听,初始化执行,该怎么配置参数
4.computed演示
<template>
<div>computed</div>
<button @click="state.count ++">count is: {{ state.count }}</button>
<div>{{ doubleCount }}</div>
</template>
<script setup>
import { reactive, computed } from 'vue'
const state = reactive({
count: 0
})
const doubleCount = computed(() => (state.count * 2))
</script>
-
nextTick演示
<template>
<div>nextTick</div>
<button @click="countClick">count is: {{ state.count }}</button>
<div v-if="state.count" id="divEle">{{ state.doubleCount }}</div>
</template>
<script setup>
import { reactive, nextTick } from 'vue'
const state = reactive({
count: 0,
doubleCount: 0
})
const countClick = () => {
state.count ++
nextTick(() => {
state.doubleCount = state.count * 2
const divEle2 = document.getElementById('divEle')
console.log('divEle2::', divEle2);
});
const divEle1 = document.getElementById('divEle')
console.log('divEle1::', divEle1);
}
</script>
-
props演示
<template>
<div>defineProps</div>
<div>{{ msg }}</div>
</template>
<script setup>
import { reactive, defineProps } from 'vue'
defineProps({
msg: String
})
const state = reactive({
count: 0,
})
</script>
- 以上看着不习惯,setup还可以这样写
<template>
<div>defineProps</div>
<div>{{ msg }}</div>
</template>
<script>
import { reactive, defineProps } from 'vue'
export default {
props: ['msg'],
setup() {
const state = reactive({
count: 0,
})
return { state }
}
}
</script>
四、vite打包信息
- vite打包是杠杠的大拇指
- 但是,vite打包虽然小,单并不支持ie,目前在咱们项目中无法使用
五、Breadcrumb 面包屑迁移
完全迁移(composition api jsx篇)
- 迁移前
<template>
<div class="p-breadcrumb">
<section class="p-breadcrumb-item" v-for="(item, i) in data" :key="i+'-'+item.id">
<article
:class="[
'p-breadcrumb-item-text',
(value?value===item.id:i===data.length-1)&&'p-breadcrumb-item-active',
(i>0&&i<data.length-1)&&'p-breadcrumb-item-width',
(i===data.length-1)&&'p-breadcrumb-item-max-width'
]"
v-ptitle:isText:true="item.name"
@click="breadcrumbClick(item.id)"
@mouseenter="TextEllipsis"
>{{item.name}}</article>
<article class="p-breadcrumb-arrow" v-if="i<data.length-1">
<ArrowRight />
</article>
</section>
</div>
</template>
<script>
import ArrowRight from '../static/iconSvg/arrow_right.svg';
import TextEllipsis from '../static/utils/TextEllipsis';
export default {
name: 'Breadcrumb',
components: { ArrowRight },
props: {
// 数据列表
data: {
type: Array,
default: () => []
},
// 当前高亮显示的id
value: {
type: String,
default: ''
}
},
data() {
return {
titleShow: false // 是否显示title
};
},
methods: {
TextEllipsis,
/**
* 点击某项执行的钩子
* @param id
*/
breadcrumbClick(id) {
if (this.value) this.$emit('input', id);
}
}
};
</script>
- 迁移后
import { defineComponent } from 'vue';
import TextEllipsis from '../static/utils/TextEllipsis';
import ArrowRight from '../static/iconSvg/arrow_right.svg';
const ArrowRightDom = (
<article className="p-breadcrumb-arrow">
<ArrowRight/>
</article>
);
const Breadcrumb = defineComponent({
name: 'Breadcrumb',
props: {
// 数据列表
data: {
type: Array,
default: () => []
},
// 当前高亮显示的id
modelValue: {
type: String,
default: ''
}
},
emits: ['change', 'update:modelValue'],
setup(props, { emit }) {
const breadcrumbClick = (id) => {
if (props.modelValue) emit('update:modelValue', id);
else emit('change', id);
};
return () => {
const { data, modelValue } = props;
return (
<div class="p-breadcrumb">
{
data.map((item, i) => (
<section class="p-breadcrumb-item" key={`${i}-${item.id}`}>
<article class={{
'p-breadcrumb-item-text': true,
'p-breadcrumb-item-active': (modelValue ? modelValue === item.id : i === data.length - 1),
'p-breadcrumb-item-width': (i > 0 && i < props.data.length - 1),
'p-breadcrumb-item-max-width': (i === data.length - 1)
}}
onClick={() => breadcrumbClick(item.id)}
onMouseEnter={TextEllipsis}
>{item.name}</article>
{(i < data.length - 1) && <ArrowRightDom/>}
</section>
))
}
</div>
);
};
}
});
- 注意
- class类名的绑定 - 与react中不一样的是,vue中支持对象、数组
- props - 必须接收
- emits - 需申明提交方式
- 事件 - 事件绑定需要on...开头
保守迁移(option api)
<template>
<div class="p-breadcrumb">
<section class="p-breadcrumb-item" v-for="(item, i) in data" :key="i+'-'+item.id">
<article
:class="[
'p-breadcrumb-item-text',
(modelValue?modelValue===item.id:i===data.length-1)&&'p-breadcrumb-item-active',
(i>0&&i<data.length-1)&&'p-breadcrumb-item-width',
(i===data.length-1)&&'p-breadcrumb-item-max-width'
]"
@click="breadcrumbClick(item.id)"
@mouseenter="TextEllipsis"
>{{item.name}}</article>
<article class="p-breadcrumb-arrow" v-if="i<data.length-1">
<ArrowRight />
</article>
</section>
</div>
</template>
<script>
import ArrowRight from '../static/iconSvg/arrow_right.svg';
import TextEllipsis from '../static/utils/TextEllipsis';
export default {
name: 'Breadcrumb',
components: { ArrowRight },
props: {
/**
* 数据列表
*/
data: {
type: Array,
default: () => []
},
/**
* 当前高亮显示的id
*/
modelValue: {
type: String,
default: ''
}
},
emit: ['update:modelValue'],
data() {
return {
titleShow: false // 是否显示title
};
},
methods: {
TextEllipsis,
/**
* 点击某项执行的钩子
* @param id
*/
breadcrumbClick(id) {
if (this.modelValue) this.$emit('update:modelValue', id);
}
}
};
</script>
- 问题:
vue3当中很多废弃api,不能保证所有组件迁移成功(研究中)
六、v-model与v-show写法
- 截图来之某乎,大家可以下去试下,在jsx中并没什么ly
.vue | v-show | v-model | v-model:title | v-model:title.func |
---|---|---|---|---|
.jsx | v-show | v-model | v-model={[val, 'title']} | v-model={[val, 'title', ['func']]} |
七、全局变量
版本 | 变量 | 获取 |
---|---|---|
vue2 | Vue.prototype.$xxx = xxx | this.$xxx |
vue3 | app.config.globalProperties.$xxx = xxx | getCurrentInstance().ctx.$xxx |
八、两个好玩的组件
-
Teleport 传送门
- 有这样的场景,我们在做业务的时候,经常会遇到层级(z-index)问题、或者我们项把组件挂在到body下
示例:<Teleport to="body"> <div>xxx</div> </Teleport>
其中to参数值可以指向任何一个容器(容器建议具有唯一性)
- 有这样的场景,我们在做业务的时候,经常会遇到层级(z-index)问题、或者我们项把组件挂在到body下
-
Suspense 用作处理异步占位
- 最常见的当数据没有回来时我们需要一个占位内容,通常是loading或骨架屏
示例:<Suspense> <template #default> <div>主内容(异步加载内容)</div> </template> <template #fallback> <div>loading</div> </template> </Suspense>
此处为固定写法,目前官网文档还不完善,且Suspense api可能会改变,别问为什么我知道,网上抄的
- 最常见的当数据没有回来时我们需要一个占位内容,通常是loading或骨架屏
九、以上思考问题回复
- 思考1:怎么用ref获取dom
回复:const dom = ref(null); <div ref={dom}></div>
- 思考2:以上可以看出,如果用reactive声明n个变量,在dom中使用都要加上state.xxx,岂不是很麻烦,
现在我要这样的效果 <div>count is: {{ count }}</div>,您会怎么做?
回复:const state = reactive({ params1: '111', params2: '222', params3: '333' }) return { ...toRefs(state) }
- 思考3:
- 我想同时监听多个变量,该怎么做
回复:watch([() => state.params1,() => state.params2,() => state.params3], (n, o) => { console.log(n, o); }); const clickHandler = () => { state.params1 = '1111+1' }
- 深度监听,初始化执行,该怎么配置参数
回复:
watch([() => state.params1,() => state.params2,() => state.params3], (n, o) => { console.log(n, o); }, { deep: true, immediate: true });
- 我想同时监听多个变量,该怎么做
总结
- vue3支持大部分在vue2中的option api,就好比在react17中既可以使用class component也可以使用hooks
- vue3 api变化大,其中所提供的api远不止本文这些,本文只做了一个简单的入门介绍
- vue3目前暂不支持ie11-,尤老师本计划在20年第四季度完成这事的,现在来看,不知道啥时候能得到尤老师的好消息
- vue3的生态是一个浩大的工程,官方正在奋力解决,小伙伴们不要慌
祝各位工作愉快
end~