Vue 3 的基本使用

275 阅读3分钟

一、推荐的插件

1. Volar : Vue3 多个根节点不会报错; 编辑器隔离。
1. Vue 3 Sinppets:  代码自动补全

二、创建 Vue 3 项目

  1. vue create <project> : 选择 Vue 3 项目

  2. npm init vite-app <project> : 使用 Vite 创建 Vue 3 项目

  3. 项目中

    //  main.ts :
    import { createApp }  from 'vue'
    import App from './App.vue'
    createApp(App).mount('#app')
    
    // App.vue
    // 1. 不需要根标签; 2. 使用 defineComponent 定义组件
    //Vue2组件中的html模板中必须要有一对根标签,Vue3组件的html模板中可以没有根标签
    <template>
      <img alt="Vue logo" src="./assets/logo.png">
      <!-- 使用子级组件 -->
      <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
    </template>
    
    <script lang="ts">
    // 这里可以书写TS代码
    
    // defineComponent函数,目的是定义一个组件 内部可以传入一个配置对象
    import { defineComponent } from 'vue';
    //引入子级组件
    import HelloWorld from './components/HelloWorld.vue';
    
    // 暴露出去一个定义好的组件
    export default defineComponent({
      // 当前组件的名字
      name: 'App',
      // 注册组件
      components: {
        // 注册一个子级组件
        HelloWorld,
      },
    });
    </script>
    
    
    
  4. Composition API : 将原分散在 Options API (data/computed/methods/props等) 中的数据组合起来。

三、 Vue 3 的基本使用

  1. setup(): Composition API 的入口函数,生命周期(= (beforeCreate + created)),此时实例还未创建,没有this。

    setup函数如果返回对象, 对象中的 属性方法 , 模板 中可以直接使用。

    //templete
    <div>{{number}}</div>
    
    //JS
    setup() {
      const number = 18;
      return {
        number,
      };
    },
    

    setup(props, {attrs, slots, emit }) : 参数

  2. ref : 定义一个响应式的数据(一般用来定义一个基本类型的响应式数据UndefinedNullBooleanNumberString)。 script中操作数据需要使用xxx.value的形式,而模板中不需要添加.value

  3. reactive: 定义多个数据的响应式,接收一个普通对象然后返回该普通对象的响应式代理器对象(Proxy),响应式转换是“深层的”:会影响对象内部所有嵌套的属性,所有的数据都是响应式的。

  4. computed() : 计算属性,返回一个ref类型的对象

  5. toRefs: 把一个响应式对象转换成普通对象,该普通对象的每个属性都是一个 ref

  6. provide 与 inject: 实现跨层级组件(祖孙)间通信

    // 父组件
    setup () {
    	const color = ref('red')
    	provide('color', color)
    	return {
    		color
    	}
    }
    
    // 跨级子组件
    setup () {
    	const color = inject('color')
    	return {
    		color
    	}
    }
    

四、其他特性

  1. Teleport(瞬移): 可以把子组件或者 DOM节点 插入到任何你想插入到的地方去。

    <teleport to="body"></teleport>
    
  2. Suspense(不确定的): 在等待异步组件时渲染一些后备内容。

    <Suspense>
    	<template v-slot:default>
    		<!-- 异步组件 -->
    		<AsyncComp />
    	</template>
    	<template v-slot:fallback>
    		<!-- 后备内容 -->
    		<h1>Loading...</h1>
    	</template>
    </Suspense>
    
    // 异步组件
    const AsyncComp = defineAsyncComponent(() => import('./AsyncComp.vue'))
    
  3. 响应式数据的判断:

    1. isRef: 检查一个值是否为一个 ref 对象;
    2. isReactive: 检查一个对象是否是由 reactive 创建的响应式代理;
    3. isReadonly: 检查一个对象是否是由 readonly 创建的只读代理;
    4. isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理。

五、script setup 语法糖

  1. 组件只需引入无需再注册;

  2. 属性和方法也不用再 return 返回;

  3. 不需要 export default {} ;

  4. 不需要 setup()

  5. props / emit / attrs ,使用语法糖提供的新API: defineProps, defineEmit, useContext;

    <script setup>
    import Child from './child.vue'
    
    const handleClick = (ctx) => {
    	console.log(ctx)
    }
    </script>
    

    注意:如果在父组件中通过 ref='xxx' 的方法来获取子组件实例,子组件使用了script setup 语法糖,那么子组件的数据需要用 expose 的方式导出,否则会因为获取不到数据而报错。

    // 子组件
    <script setup>
        import { ref, defineOptions } from 'vue'
        
        const { expose } = defineOptions()
        
        const count = ref(0)
        
        expose({ count })
        
    </script>
    
  6. Emit 派发事件可以对参数进行验证

    export default {
      name: '',
      emits: {
        sonClick: (value) => {
          if (value === 1) {
            return true
          } else {
            return false
          }
        },
      },
      setup(props, { emit }) {
        const msg = ref('hello')
        const handleClick = (value) => {
          emit('sonClick', value)
        }
        return {
          msg,
          handleClick,
        }
      },
    
  7. 跨组件通讯 mitt.js 【event bus】

    // 安装
    npm i mitt -s
    
    // 封装 hook, mitt.js
    import mitt from 'mitt'
    const emitter = mitt()
    export default emitter 
    

    emitter.on() / emitter.off() / emitter.emit()

  8. 其他:

    Vue3 移除了 filter ; 获取组件实例方法 getCurrentInstance();

六、Vuex

  1. Vue 3 使用 Vuex 4.x

    yarn add vuex@next --save
    
  2. 关于vuex的基本使用:

    import Vuex from 'vuex'
    const store = Vuex.createStore({
    	state: {
    		// ...
    	}
    })
    export default store
    
    // main.ts
    import store from './store'
    createApp(App).use(store).mount('#app')
    
    // vuex 的使用 
    import { useStore } from 'vuex'
    setup () {
    	const store = useStore()		// == this.$store
    	store.dispatch()				// 模板中使用 {{ store.state.xxx }}
    }
    

七、Vue Router

  1. 关于Vue Router

    import { createRouter } from 'vue-router'
    const router = createRouter({
    	// ...
    })
    
  2. 使用 history 配置取代 mode 选项

    每一个模式都由从 vue-router 导出的函数一一对应:

    • history ——> createWebHistory
    • hash ——> createWebHash
    • abstract ——> createMemoryHistory
    import { createRouter, createWebHistory } from 'vue-router'
    
    export const router = createRouter({
    	history: createWebHash(),
    	routes
    })
    
    export default router
    
  3. 使用 router

    // main.ts
    import router from './router'
    import store from './store'
    createApp(App)
    	.use(router)
    	.use(store)
    	.mount('#app')
    
  4. 取消(*) 通配符路由

    // 不再适用
    {
    	path: "*"
    }
    
    // 改为必须使用自定义的 regexp 参数来定义所有路由(*, /*)
    {
    	path: '/:pathMatch(.*)'
    }
    
  5. <keep-alive>写法变更

    // 原写法
    <keep-alive v-if="$route.meta.keepAlive">
    	<router-view></router-view>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"></router-view>
    
    // 新写法  :is 用来绑定指定的组件,与路由对应的页面绑定
    <router-view v-slot="{ Component }">
    	<keep-alive>
    		<component :is="Component" v-if="$route.meta.keepAlive">
    	</keep-alive>
    	<component	:is="Component" v-if="$route.meta.keepAlive"/>
    </router-view>
    
    
  6. 新增 useRoute , useRouter

    // 获取路由中的 id
    import { useRoute, useRouter } from 'vue-router'
    
    setup () {
    	const { params: { id }} = useRoute()		// == this.$route
    	
    	const router = useRouter()		// == this.$router
    	router.push('/login')
    	
    	return {
    		id 
    	}
    }