Vue 3.0 中文文档 链接 (现有用户直接到迁移指南 迁移链接)
支持vue3的组件库: Element-plus Vant 3.0 Ant-design-vue
vue2两个问题:对复杂组件难以维护;对typescript支持不够;(此时就可以用vue3)
1)Composition API
90%的vue2(optionsAPI)代码在vue3(Composition API)中不受影响
// 能用compositioin抽逻辑就不要用mixin,因为composition可以完全替代mixin
即组合使用reactive ref watchEffect这三个
2)Fragment碎片
不再限制单文件组件只能有一个根节点
3)teleport
4)suspense
5)完全支持ts,支持tsx。体验效果很好
// vue3.0 是由ts重写的
6)custom renderer API
// 自定义 render 函数的 API
7)vite热加载,相比webpack基本加载在100ms以内
一: 使用vite初始化vue3项目
npm install create-vite-app --save-dev //也可以全局下载
npx create-vite-app project-name // 项目
npm install
npm run dev
npm run build
// 下载插件
npm i vue-router@next
npm i vuex@next
npm i vant@next -S
// src/srouter.js
import {
createRouter, createWebHistory } from 'vue-router'
import Home from './components/home/Home.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
// route -> routes
{
path: '/',
name: 'home',
component: Home,
}
],
})
export default router
// src/main.js
import {
createApp } from 'vue'
import App from './App.vue'
import './index.css'
import router from './router'
// import store from './store'
const app = createApp(App)
app.use(router)
app.mount('#app')
// app.vue
<template>
<!-- <img alt="Vue logo" src="./assets/logo.png" /> -->
<!-- <HelloWorld msg="Hello Vue 3.0 + Vite" /> -->
<router-view> </router-view>
</template>
<script>
// import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
// HelloWorld
}
}
</script>
就可以创建一个vue3项目了
下载后,就使用vant组件库
import {
createApp } from 'vue'
import App from './App.vue'
import './index.css'
import router from './router'
// 引入vant组件和全局样式
import {
Button } from 'vant';
import 'vant/lib/index.css';
const app = createApp(App)
app.use(router)
// 注册vant组件
app.use(Button)
app.mount('#app')
setup使用
<template>
<div>
home
</div>
</template>
<script>
import {
} from 'vue'
export default {
name: 'home',
setup () {
// 在created(组件初始化)钩子前执行,因为拿不到created和methods所以setup中没有this;
// 且setup函数只能是同步的,但是可以在setup中使用Composition API
console.log('setup')
},
created(){
console.log('created')
}
}
</script>
二: 使用vue-cli创建vue3项目
npm i -g @vue/cli // vue-cli4.5以上的版本才能创建vue3(vue --version查看版本)
vue ui
--自定义预设-选择功能-选择vue3 previe,不要选class-创建
文件描述
- ts的语言服务需要.d.ts文件来识别类型,这样才能做到相应的语法检查和智能提示
使用
–ref,computed
<h1>{
{
count }}</h1>
<h1>{
{
count2 }}</h1>
<button @click="add">增加</button>
import {
ref, defineComponent, computed } from 'vue'
setup() {
const count = ref(0)
const count2 = computed(() => {
return count.value * 2
})
function add() {
count.value++
}
return {
count,
add,
count2
}
}
—reactive, toRefs
<h1>{
{
count }}</h1>
<h1>{
{
double }}</h1>
<button @click="increase">增加</button>
import {
computed, reactive, toRefs } from 'vue'
interface DataProps {
count: number;
double: number;
increase: () => void;
}
setup() {
const data: DataProps = reactive({
count: 0,
increase: () => {
data.count++},
double: computed(() => data.count * 2),
})
const refData = toRefs(data) // toRefs可以使{}对象类型下每个属性具有响应性
return {
...refData
}
}
–修改对象属性和数组索引也具有响应式
<ul>
<li v-for="(item, index) in list" :key="index">{
{
item }}</li>
</ul>
<div>{
{
obj.name}}</div>
import {
reactive, toRefs } from 'vue'
interface DataProps {
list: number[]
obj: {
name?: string }
}
setup() {
const data: DataProps = reactive({
list: [1, 2, 3, 4],
obj: {
},
})
data.list[2] = 0
data.obj.name = '张三'
const refData = toRefs(data) // toRefs可以使{}对象类型下每个属性具有响应性
return {
...refData,
}
}
import {
ref, onMounted } from 'vue'
setup () {
onMounted(() => {
// 初始化echarts
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
})
}
(onRenderTracked, onRenderTriggered检测数据的钩子)
import {
onMounted, onUpdated } from 'vue'
setup() {
onMounted(()=>{
console.log('onMounted')
})
onUpdated(()=>{
console.log('数据更新触发onUpdated')
})
return {
}
}
– watch
<h1>{
{
count }}</h1>
<h1>{
{
num }}</h1>
<button @click="increase">增加count</button>
<button @click="numFn">增加num</button>
<button @click="updateTitle">更新</button>
import {
ref,
defineComponent,
reactive,
toRefs,
watch,
} from 'vue'
interface DataProps {
count: number
increase: () => void
}
setup() {
const data: DataProps = reactive({
count: 0,
increase: () => {
data.count++
},
})
let num = ref('')
function numFn() {
num.value = 'abc'
}
function updateTitle() {
watch([num, () => data.count], (newOld, oldVal) => {
// 直接写是具有响应式的属性 // 函数形式:可以监控对象内的一个属性
document.title = 'update' + data.count
})
}
const refData = toRefs(data) // toRefs可以使{}对象类型下每个属性具有响应性
return {
...refData,
num,
updateTitle,
numFn,
}
}
– vue抽离逻辑模块(自定义hooks)
// src/hooks/useMousePosition.ts
import {
ref, onMounted, onUnmounted } from 'vue'
function useMousePosition() {
const x = ref(0)
const y = ref(0)
const updateMouse = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
document.addEventListener('click', updateMouse)
})
onUnmounted(() => {
document.removeEventListener('click', updateMouse)
})
return {
x, y}
}
export default useMousePosition
// src/App.vue
import useMousePosition from './hooks/useMousePosition'
setup() {
const {
x, y } = useMousePosition()
return {
}
}
–发送请求
/src/hooks/useURLLoader
import {
ref } from 'vue'
import axios from 'axios'
function useURLLoader<T>(url: string) {
const result = ref<T | null>(null)
const loading = ref(true)
const loaded = ref(false)
const error = ref(null)
axios.get(url).then((rawData) => {
loading.value = false
loaded.value = true
result.value = rawData.data
}).catch(e => {
error.value = e
loading.value = false
})
return {
result,
loading,
error,
loaded
}
}
export default useURLLoader
//src/App.vue
<h1 v-if="loading">Loading!...</h1>
<img v-if="loaded" :src="result.message" />
import useURLLoader from './hooks/useURLLoader'
setup() {
const {
result, loading, loaded } = useURLLoader(
'https://dog.ceo/api/breeds/image/random'
)
return {
result,
loading,
loaded,
}
}
– vue内置组件Suspense(展示请求后的组件)
/src/App.vue
<Suspense>
<!-- Suspense包裹请求成功的组件 -->
<template #default>
<div>
<async-show />
<dog-show />
</div>
</template>
<template #fallback>
<h1>Loading !...</h1>
</template>
</Suspense>
import AsyncShow from './components/AsyncShow.vue'
import DogShow from './components/DogShow.vue'
components:{
AsyncShow,
DogShow
},
setup() {
const error = ref(null)
onErrorCaptured((e: any) => {
// 抓取请求错误
error.value = e
alert(e)
return true // 向上传播
})
return {
error,
}
}
// src/components/AsyncShow
<template>
<h1>{
{
result}}</h1>
</template>
<script lang="ts">
import {
defineComponent } from 'vue'
export default defineComponent({
setup() {
return new Promise((resolve) => {
setTimeout(() => {
return resolve({
result: 42
})
}, 3000)
})
}
})
</script>
// src/components/DogShow
<template>
<img :src="result && result.message">
</template>
<script lang="ts">
import axios from 'axios'
import {
defineComponent } from 'vue'
export default defineComponent({
async setup() {
const rawData = await axios.get('https://dog.ceo/api/breeds/image/random')
return {
result: rawData.data
}
}
})
</script>
–teleport (根组件展示)
src/components/Modal
<template>
<teleport to="#modal">
<div id="center" v-if="isOpen">
<h2><slot>this is a modal</slot></h2>
<button @click="buttonClick">Close</button>
</div>
</teleport>
</template>
<script lang="ts">
import {
defineComponent } from 'vue'
export default defineComponent({
props: {
isOpen: Boolean,
},
// emits: {
// 'close-modal': null // 可以添加验证事件名称,不验证是null
// },
emits: ["close-modal"],
setup(props, context) {
const buttonClick = () => {
context.emit('close-modal')
}
return {
buttonClick
}
}
})
</script>
<style>
#center {
width: 200px;
height: 200px;
border: 2px solid black;
background: white;
position: fixed;
left: 50%;
top: 50%;
margin-left: -100px;
margin-top: -100px;
}
</style>
/src/App.vue
<button @click="openModal">Open Modal</button><br />
<modal :isOpen="modalIsOpen" @close-modal="onModalClose">
My Modal !!!!</modal
>
import Modal from './components/Modal.vue'
components: {
Modal,
},
setup() {
const modalIsOpen = ref(false)
const openModal = () => {
modalIsOpen.value = true
}
const onModalClose = () => {
modalIsOpen.value = false
}
return {
modalIsOpen,
openModal,
onModalClose,
}
}
// publice/index.html
<div id="app"></div>
<div id="modal"></div>
–vue全局配置
-全局api
Vue.config — app.config
config.productionTip被删除
config.ignoreElements 改名 config.isCustomElement
config.keyCodes被删除
-全局注册类
Vue.component - app.component
Vue.directive - app.directive
-行为拓展类api
Vue.mixin - app.mixin
Vue.use - app.use
-treeshaking api
//vue2
import Vue from 'vue'
Vue.nextTick(()=>{
})
const obj = Vue.observable({
})
//vue3
import Vue, {
nextTick, observable } from 'vue'
Vue.nextTick // undefined
nextTick(()=>{
})
const obj = observable({
})
-setup中跳转
import {
useRouter } from "vue-router";
setup(){
const router = useRouter();
function login(){
router.push("/home");
}
}
setup获取传递的参数
https://blog.csdn.net/weixin_40461134/article/details/108888438