Vue3.0从入门到一骑绝尘

一、vue3.0快速上手

1、Vue3简介

Vue3.0支持大多数的Vue2的特性,Vue3中设计了一套强大的composition组合API代替Vue2中的optionAPI,复用性更强大了,对TypeScript有更好的支持。

2、Vue3带来了什么?

1、性能的提升

  • 打包大小减少了41%
  • 初次渲染块55%,更新渲染块133%
  • 内存减少54%

2、源码的升级

  • 使用Proxy代替defineProperty实现响应式
  • 重写虚拟DOM的实现和Tree-Shaking

3、拥抱TypeScript

  • Vue3可以更好的支持ypeScript

4、新的特性

1、Composition API(组合API)

  • setup配置
  • ref与reactive
  • watch与watchEffect
  • provide与inject

2、新的内置组件

  • Fragment
  • Teleport
  • Suspense

3、其他改变

  • 新的生命周期钩子
  • data选项应始终被声明为一个函数
  • 移除keyCode支持作为v-on的修饰符

二、创建项目

2.1Vue-cli脚手架搭建项目

(1)首先查看你的版本

## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue -V
## 安装获取升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue-test
## 启动
cd vue_test
npm run serve

注意:yarn安装npm install -g yarn

Vue3.0从入门到一骑绝尘_第1张图片

2.2、使用vite创建

  • 什么是vite?—— 是Vue团队打造的新一代前端构建工具。
  • 优势如下:
    1、开发环境中,无需打包操作,可快速的冷启动。
    2、轻量快速的热重载(HMR)。
    3、真正的按需编译,不再等待整个应用编译完成。
npm init @vitejs/app <项目名>

三、Composition API

3.1是什么?

Composition API也叫组合式API,是Vue3.0的新特性。

通过创建Vue组件,我们可以将接口的可重复部分及其功能提取到可重复的代码部分及其功能提取到可重用的代码段中。

3.2为什么使用CompositionAPI?

Vue3.0从入门到一骑绝尘_第2张图片

3.3函数

Vue3.0从入门到一骑绝尘_第3张图片

3.4(一)setup

setup()函数是vue3.0中,专门为组件提供的新属性,它为我们使用vue3的CompositionAPI新特性提供了统一的入口。

  • 1、组件中所用到的:数据、方法等等,均要配置在setup中。
  • 2、若返回一个对象,则对象中的属性、方法,在模板中均可以直接使用。若返回一个渲染函数:则可以自定义渲染内容。
<template>
  <h1>博主的信息</h1>
  <h2>姓名:{{name}}</h2>
  <h2>年龄:{{age}}</h2>
  <h2>性别:{{gender}}</h2>
  <button @click="sayInfo">显示信息</button>
</template>

<script>
// import {h} from 'vue'
export default {
  name: "App",
  //此处只是测试一下setup,暂时不考虑响应式的问题。
  setup(){
    // 数据
    let name = "YK菌"
    let age = 18
    let gender = "男"

    // 方法
    function sayInfo(){
      alert(`你好${name},你太厉害了吧`)
    }
    // 返回一个对象(常用)
    return {
      name,age, gender,sayInfo
    }
    // 返回一个函数(渲染函数)
    // return ()=> h('h1','YK菌yyds')
  }
};
</script>
props:组件传入的属性 context:上下文对象

Vue3.0从入门到一骑绝尘_第4张图片

3.5(二)ref函数

作用: 定义一个响应式的数据
语法: const xxx = ref(initValue)

  • 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)。
  • JS中操作数据: xxx.value
  • 模板中读取数据:不需要.value,直接:
    {{xxx}}

备注:

  • 接收的数据可以是:基本类型、也可以是对象类型。
  • 基本类型的数据:响应式依靠的是类上的getter与setter完成的(我们等下看下源码你就知道了)。
  • 对象类型的数据:内部 “ 求助 ”了Vue3.0中的一个新函数—— reactive函数。
<template>
  <!-- <h3>数量:{{num}}</h3> -->
  <h3>count数量:{{count}}</h3>
  <input type="text" v-model="count">
  <button @click="getCount()">获取</button>
</template>
<script>
    import {ref} from 'vue'
    export default {
        //option API方式
        // data(){
        //     return{
        //         num:0
        //     }
        // }
        //composition API方式
        setup(){//data methods computed watch都是写在setup中
            //直接这样定义 不是响应式的数据
            // const count = 0;
            
            //创建响应式的数据对象 我们的count 给初始值为0
            const count = ref(0)

            let getCount = ()=>{
                //如果要访问ref() 创建出来响应式数据对象的值 必须通过.value属性才可以
                console.log(count.value)
            }
            //模板中要使用这些变量和方法 都需要调用,所以需要return
            return{
                count,getCount
            }
        }
    }
</script>
<style>
</style>

3.5(三)reactive

  • 作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
  • 语法:const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
  • reactive定义的响应式数据是“深层次的”。
  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。

3.6(四)reactive对比ref

1、从定义数据角度对比

ref用来定义:基本类型数据
reactive用来定义:对象(或数组)类型数据
备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象

2、从原理角度对比

ref通过类中的的gettersetter来实现响应式(数据劫持)。
reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。

3、从使用角度对比

ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value
reactive定义的数据:操作数据与读取数据:均不需要.value

3.7(五)toRefs

toRefs将响应式对象转换为普通对象,其中结果对象的每个property都是指向原始对象相应property的ref。

  • 作用:创建一个ref对象,其value值指向另一个对象中的某个属性。
  • 语法:const name = toRef(person,'name')
  • 应用: 要将响应式对象中的某个属性单独提供给外部使用时。
  • 扩展:toRefstoRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)

3.8(六)computed





3.9(七)watch

watch()函数用来监视某些数据项的变化,从而触发某些特定的操作,使用之前需要按需导入:

注意:
1、监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
2、监视reactive定义的响应式数据中某个属性时:deep配置有效。

export default{
		setup(props,context){//composition API的入口
			const num = ref(0)
			const str = ref("测试")
			const state = reactive({
				id:101,
				uname:'莫愁'
			})
			
			//只要num有变化 会触发watch的回调 watch会在创建时自动调用
			// watch(()=>{console.log(num.value)})
			
			/* val:新的值 oval:旧的值 */
			watch(num,(val,oval)=>{
				console.log(val,oval)
				console.log("c num:",num.value)
			},{//第二个参数obj immediate deep
				immediate:false //默认就是只有数据改变时才会监听,第一次不会执行,设置true第一次也会执行
			})
			
			//侦听state下的id,数据的变化
			watch(state,(val,oval)=>{
				console.log("id:",val.id,oval)
			},{
				immediate:true ,//默认就是只有数据改变时才会监听,第一次不会执行,设置true第一次也会执行
				deep:true,//开启深度侦听 能够侦听到对象的属性值的变化
			})
			
			//单个侦听state下的uname
			watch(()=>state.uname,(uname,p)=>{
				console.log(uname,p)
			},{
				immediate:true ,//默认就是只有数据改变时才会监听,第一次不会执行,设置true第一次也会执行
			})
			//const s = toRefs(state)  watch(s.id,()=>{})  等于 ()=>state.id
			
			//多个侦听数据
			const stop = watch([()=>state.id,()=>state.uname],([id,uname],[oid,oname])=>{
				console.log("id:",id,oid)
				console.log("uname",uname,oname)
			})			
			return{
				num,stop,
				...toRefs(state)
			}
		}
	}

3.10(八)watchEffect函数【用到哪个、监视哪个】

watch的套路是:既要指明监视的属性,也要指明监视的回调。
watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
watchEffect有点像computed

  • 1、但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
  • 2、而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。

Vue3.0从入门到一骑绝尘_第5张图片

3.11(九)API

Vue3.0从入门到一骑绝尘_第6张图片

Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:

  • beforeCreate===>setup()
  • created=======>setup()
  • beforeMount===>onBeforeMount
  • mounted=======>onMounted
  • beforeUpdate===>onBeforeUpdate
  • updated =======>onUpdated
  • beforeUnmount ==>onBeforeUnmount
  • unmounted =====>onUnmounted

3.12(十)自定义 hook函数【重点】

  • 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。
  • 类似于vue2.x中的混合机制mixin
  • 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。

1、创建一个hooks文件夹,里面创建文件usePoint.js

import { reactive, onMounted, onBeforeUnmount } from "vue";
export default function() {
  //实现鼠标“打点”相关的数据
  let point = reactive({
    x: 0,
    y: 0,
  });

  //实现鼠标“打点”相关的方法
  function savePoint(event) {
    point.x = event.pageX;
    point.y = event.pageY;
    console.log(event.pageX, event.pageY);
  }

  //实现鼠标“打点”相关的生命周期钩子
  onMounted(() => {
    window.addEventListener("click", savePoint);
  });

  onBeforeUnmount(() => {
    window.removeEventListener("click", savePoint);
  });

  return point;
}

2、在组件中使用

<template>
	<h2>我是HelloWorld组件</h2>
	<h2>当前点击时鼠标的坐标为:x:{{point.x}},y:{{point.y}}</h2>
</template>

<script>
	import usePoint from '../hooks/usePoint'
	export default {
		name:'HelloWorld',
		setup(){
			const point = usePoint()
			return {point}
		}
	}
</script>

四、其它 Composition API

1、shallowReactiveshallowRef

  • shallowReactive:只处理对象最外层属性的响应式(浅响应式)。

  • shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理。

  • 什么时候使用?

    1、如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive
    2、如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===>shallowRef

2、readonlyshallowReadonly

  • readonly: 让一个响应式数据变为只读的(深只读)。
  • shallowReadonly: 让一个响应式数据变为只读的(浅只读)。
  • 应用场景: 不希望数据被修改时。

3、toRawmarkRaw

toRaw:

  • 作用: 将一个由reactive生成的响应式对象转为普通对象
  • 使用场景: 用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。

markRaw:

  • 作用: 标记一个对象,使其永远不会再成为响应式对象。
  • 应用场景: ①有些值不应被设置为响应式的,例如复杂的第三方类库等。②当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。

4、customRef

  • 作用: 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。
  • 实现防抖效果
<template>
  <input type="text" v-model="keyWord" />
  <h3>{{ keyWord }}</h3>
</template>

<script>
import { customRef } from "vue";
export default {
  name: "App",
  setup() {
    //自定义一个ref——名为:myRef
    function myRef(value, delay) {
      let timer;
      return customRef((track, trigger) => {
        return {
          get() {
            console.log(`有人从myRef这个容器中读取数据了,我把${value}给他了`);
            track(); // 通知Vue追踪value的变化(提前和get商量一下,让他认为这个value是有用的)
            return value;
          },
          set(newValue) {
            console.log(`有人把myRef这个容器中数据改为了:${newValue}`);
            clearTimeout(timer);
            timer = setTimeout(() => {
              value = newValue;
              trigger(); // 通知Vue去重新解析模板
            }, delay);
          },
        };
      });
    }

    // let keyWord = ref('hello') //使用Vue提供的ref
    let keyWord = myRef("hello", 500); //使用程序员自定义的ref

    return { keyWord };
  },
};
</script>

5、Provide&inject

1、provide

provide: 向子组件以及子孙组件传递数据。接收两个参数,第一个参数是key.即数据的名称;第二个参数为value,即数据的值

Vue3.0从入门到一骑绝尘_第7张图片

2、inject

inject: 接收父组件或祖先组件传递过来的数据。接收一个参数key,即父组件或祖先组件传递的数据名称

Vue3.0从入门到一骑绝尘_第8张图片

6、响应式数据的判断

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

五、新的组件

1、Fragment

  • 在Vue2中: 组件必须有一个根标签
  • 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
  • 好处: 减少标签层级, 减小内存占用

2、Teleport

什么是Teleport?—— Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。

3、Suspense

等待异步组件时渲染一些额外内容,让应用有更好的用户体验。

六、vue3.x中集成typescript

6.1为什么要使用ts

  • 类型检查、直接编译到原生的js、引入语法糖。
  • TypeScript的设计目的应该是解决JavaScript的“痛点”:【弱类型、没有命名空间。导致很难模块化、不适合开发大型程序】;
  • 另外它还提供了一些语法糖来帮助大家更方便地实践面向对象的编程。

6.2vue-cli(脚手架)安装ts

Vue3.0从入门到一骑绝尘_第9张图片
Vue3.0从入门到一骑绝尘_第10张图片

6.3vite安装ts

Vue3.0从入门到一骑绝尘_第11张图片

6.4定义组件

如果要让TypeScript正确推断Vue组件选项中的类型,需要使用defineComponent全局方法定义组件:Vue3.0从入门到一骑绝尘_第12张图片

6.5案例代码

<template>
	<h2>集成ts与compositionAPI一起使用</h2>
	<h4>姓名:{{uname}}</h4>
	<h4>兴趣:{{hobby}}</h4>
	<h4>年龄:{{age}}</h4>
	<h5>getUNname:{{getUNname(111)}}</h5>
	<p>{{count}}</p>
	<button @click="setCount()">setCount</button>
</template>

<script lang="ts">
	//defineComponent 启用类型校验
	import {defineComponent,reactive,toRefs,ref} from 'vue'
	//约束data中的属性与方法
	interface user{
		uname:string,	
		hobby:string,
		age:number,
		getUNname(msg:string):string
	}
	export default defineComponent ({
		setup(){
			//  三种方式:  :  <>  as
			const data:user = reactive({
				uname:"肖雅涵",
				hobby:"舞蹈",
				age:20,
				getUNname(msg){
					return msg
				}
			})
			//不支持:这种方式约束类型
			// const count:number = ref(0)
			const count= ref<number>(0)
			function setCount(){
				count.value = 123
			}
			return{
				...toRefs(data),count,setCount
			}
		}
	})
</script>
<style>
</style>

七、组合式API结合vue-router

引入setup和Vue的组合式API,开辟了新的可能性,但要充分发挥Vue Router的潜力,我们需要使用一些新的函数来代替访问this和组件内导航守卫。
因为我们在setup里面没有访问this,所以我们不能在直接访问this.$router或this.$route。作为替代,我们使用useRouter和useRoute函数。

//引入路由
import {useRouter,useRoute} from 'vue-router'
export default{
	setup(){
		const router = useRouter()//等同于this.$router
		const route = useRoute()//等同于this.$route
		
	}
}

八、组合式API结合vuex

如果在使用Vue 中的 组合式API进行编写组件,就不能延续之前的写法(如: this. s t o r e ) 。 由 于 我 们 无 权 访 问 s e t u p 的 内 部 t h i s , 因 此 要 在 s e t u p 中 使 用 s t o r e , 可 以 调 用 该 u s e S t o r e 函 数 。 这 等 效 t h i s . store)。由于我们无权访问setup的内部this,因此要在setup中使用store,可以调用该useStore函数。这等效this. store)访setupthissetup使storeuseStorethis.store于使用Option API在组件内进行检索。

8.1setup中访问vuex

请注意,在模板中我们仍然可以访问$store,所以不需要在setup中返回store

九、resolve alias 别名定义

将会被传递到 @rollup/plugin-alias 作为它的 entries。也可以是一个对象,或一个 { find,replacement } 的数组.
当使用文件系统路径的别名时,请始终使用绝对路径。相对路径作别名值将按原样使用导致不会解析到文件系统路径中。

export default defineConfig({
  resolve: {
  alias: {
	  "@": path.resolve(__dirname, "src"),
	  "@comps": path.resolve(__dirname, "src/components"),
	  "@views": path.resolve(__dirname, "src/views"),
	  },
  },
  plugins: [vue()],
})

或者 数组的形式

import {defineConfig} from 'vite'
import path from "path";
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
	resolve: {
		alias: [{
			find: '@',
			replacement: path.resolve(__dirname, 'src')
		},
	{
		find: 'components',
		replacement: path.resolve(__dirname, 'src/components')
	}
],
},
	plugins: [vue()],
})

其他文章:【Vue】带你快速上手Vue3 - 使用 - Composition API - 响应式原理 - 新特性

Vue3.0从入门到一骑绝尘_第13张图片

你可能感兴趣的:(Vue,vue)