速懂vue3.0新特性及vue2.0区别

欢迎点击: 个人官网博客

2020年9月份beta版本出来后就一直追3.0,作为第一批吃螃蟹的人,这里把3.0的一些知识分享一下,良心之作。喜欢就收藏吧!

TypeScript传送门

目录

  • 从vue2.0到vue3.0必备知识
  • 一、简单介绍vue3.0(性能比2.x快1.2~2倍)
  • 二、常用Composition API
    • 1.setup(props,context)
    • 2.ref,reactive
      • reactive改用toRefs配合使用
      • ref获取元素
    • 3.watch,watchEffect
      • watch监听一个属性或对象
      • watch监听多个属性
      • watchEffect
    • 4.computed
      • computed有不光有get,还有set
    • 5.生命周期
    • 6. provide 和 inject(实现跨层级组件(祖孙)间通信),也可放在main.ts里面进行全局挂载使用
    • 7.自定义hook函数(即把函数抽出来复用)
    • 8.defineAsyncComponent配合Suspense异步组件使用
    • 9.新组件 Fragment及Teleport
        • Fragment
        • Teleport
    • 10.customRef, readonly,shallowReactive,shallowRef, toRaw等
    • 11、全局挂载
  • 三、setup语法糖,<script lang=“ts“ setup>
      • 1. 变量无需进行 return
      • 2. 子组件无需手动注册
      • 3. props 的接收方式变化
      • 4. emits 的接收方式变化
      • 5. attrs 的接收方式变化
      • 6. ref、defineExpose
      • 7.顶级 await 的支持
  • 四、比较Vue2与Vue3的响应式
    • vue2的响应式
    • vue3的响应式
  • 五、vue3使用vuex,vue-router
  • 六、简单总结


从vue2.0到vue3.0必备知识

一、简单介绍vue3.0(性能比2.x快1.2~2倍)

  • Vue3支持大多数的Vue2的特性。如果3.0项目中2.0跟3.0混搭写法,方法重名的话3.0优先

  • Vue3中设计了一套强大的组合APi(Compostion API)代替了Vue2中的option API ,复用性更强了。可自定义hook函数,不需要代码都写在一个template(再也不怕代码多起来,滚轮滚到手发抖了)

  • 按需编译,体积比Vue2.x更小

  • Vue3更好的支持TypeScript(TS)

  • Vue3中使用了Proxy配合Reflect 代替了Vue2中Object.defineProperty()方法实现数据的响应式(数据代理)

  • 重写了虚拟DOM,速度更快了

  • 新的组件: Fragment(片段) / Teleport(瞬移) / Suspense(不确定)

  • 设计了一个新的脚手架工具—vite,npm run dev 秒开,热重载也很快。这种开发体验真是很爽,拒绝等待。

  • 全局 API 现在只能作为 ES 模块构建的命名导出进行访问

  • Vue3可多个根组件

  • Vue3中v-if优先于v-for,移除过滤器

二、常用Composition API

import {
  defineComponent,//目的是定义一个组件,vue3如果用ts,导出时候要用 defineComponent,这俩是配对的,为了类型的审查正确
  defineAsyncComponent,//vue3中动态引入组件
  provide, //祖孙组件传参
  inject, //祖孙组件传参
  reactive, //定义多个数据的响应式,可配合torefs使用方便
  toRefs, //torefs函数可以将reavtive创建的响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref,html模板中直接使用变量显示数据
  ref, //定义一个数据的响应式(一般是基本数据类型),通过.value获取到值,如果是object之类会自动转化为reactive
  computed, //计算属性,如果只传入一个回调函数,表示的是get,可get,set
  watch, //监听一个或多个属性或对象,默认不执行---可加参数immediate表示默认执行一次,deep表示深度监视
  watchEffect, //不需要配置immediate,默认就会执行一次。监视所有回调中使用的数据
  onMounted, //生命周期
  onUnmounted,
  onUpdated,
  onBeforeUpdate,
  onBeforeMount,
  onBeforeUnmount,
  nextTick,//整个视图都渲染完毕后
  customRef,//追踪数据并告诉Vue去触发界面更新,可用于对页面更新进行一个防抖
  readonly,//数据只读
  shallowReactive,// 只处理了对象内最外层属性的响应式(也就是浅响应式)
  shallowRef,//只处理了value的响应式, 不进行对象的reactive处理
  toRaw,//返回由 reactive 或 readonly 方法转换成响应式代理的普通对象。
} from "vue";

1.setup(props,context)

setup是组合api的入口函数,函数返回对象,html模板中可以直接使用。
setup细节问题:
1.setup在beforeCreate之前执行。
速懂vue3.0新特性及vue2.0区别_第1张图片

由此推断setup在执行的时候,当前组件还没有创建出来,也意味着组件实例对象this根本不能用(undefined)
2.setup中的返回值是一个对象,内部的属性和方法是给html模板使用的。

  1. props即为父组件传递过来的值,当你在steup函数中获取值不能像vue2.0中this.值,是获取不到的,要props.值
  2. context上下文对象,里面有attrs,slots,emit
    速懂vue3.0新特性及vue2.0区别_第2张图片
import {defineComponent} from "vue";
export default defineComponent({
    setup(props, {attrs,slots,emit}){
    	console.log("this=>", this); //undefined
    	console.log(props);//父组件传过来是值
    	console.log(slots);//插槽
    	console.log(attrs); //当前组件标签上的属性,不带冒号的,带冒号是props
    	//如  text是attrs,mag是props
    	---------------------
    	const addCount = () => {
      	emit("demoHander", "我的子组件传来的");//向父组件传参,这种写法父组件@demoHander='函数'
      	//或者
      	props.demoHander('我的子组件传来的')//这种写法父组件:demoHander='函数'
    };
    return {};//必须为一个对象
  }
  });

2.ref,reactive

<template>
  <div>
    {{ count }}
    {{state.age}}
    <button @click="add"></button>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, reactive} from "vue";
export default defineComponent({
  setup() {
    // let count = 0;//这个数据不是响应式数据,(响应式数据:数据变化,页面跟着渲染)
    let count = ref(0); //ref一般定义一个数据的响应式(一般是基本数据类型,单独定义某一个常量),方法中要通过count.value获取到值,如果ref是一个对象也可以,会自动转为reactive
    ---------------------------------------------
    let obj = {
      name: "tom",
      age: 25,
      wife: {
        name: "marry",
        age: 22,
      },
    };
    let state = reactive(obj); //reactive一般定义多个数据(复杂数据类型)的响应式,如果不使用torefs的话,html模板中要使用state.age显示数据
    //方法
    const add = () => {
      count.value++;//操作ref定义的值
      state.age++;//操作reactive定义的值
      ------------------------
      // obj.age++;这种方式页面不会更新渲染,需要操作代理对象才有用
      // delete state.wife//删除某个属性,页面会更新
    };
    return {
      count,
      add,
      state //响应式数据
      //...state 不是响应式数据
      //...toRefs(state) 响应式数据
    };
  },
});
</script>

reactive不能处理简单数据类型。如reactive(10)是无法响应式的,必须是一个对象reactive({ })
ref 是一个对象也可以,会自动转为reactive。如ref({ id:10 })
注意: 解构state 或者 扩展运算符都会使数据失去响应性
速懂vue3.0新特性及vue2.0区别_第3张图片

reactive改用toRefs配合使用

toRefs()函数可以将reactive创建出来的响应式对象,转换为普通对象,只不过这个对象上的每个属性节点,都是ref()类型的响应式数据
(使用…操作符返回的对象,不会失去响应性)

<template>
  <div>
    <!-- 不使用toRefs:{{state.age}} -->
    <!--使用toRefs -->{{ age }}
  </div>
</template>

<script lang="ts">
import { defineComponent,reactive,toRefs} from "vue";
export default defineComponent({
  setup() {
    let obj = {
      name: "tom",
      age: 25,
      wife: {
        name: "marry",
        age: 22,
      },
    };
    let state = reactive(obj);
    return {
         //state
      ...toRefs(state)
    };
  },
});
</script>

ref获取元素

<template>
  <div>
    <input type="text" ref="inputRef" name="" id="" />
  </div>
</template>

<script lang="ts">
import { defineComponent, ref,} from "vue";
export default defineComponent({
  setup() {
    //通过ref自动获取焦点
    const inputRef = ref<HTMLElement | null>(null);
    onMounted(() => {
      inputRef.value && inputRef.value.focus();
    });
    return {
      inputRef,
    };
  },
});
</script>

如果项目中方法比较多时,可以这样处理,方便看
速懂vue3.0新特性及vue2.0区别_第4张图片

3.watch,watchEffect

watch监听一个属性或对象

setup() {
  let state = reactive({
      fristName: "东方",
      laetName: "不败",
      fallName3:""
    });
    ------------方法一
   watch(state,({fristName,laetName})=>{
        fallName3.value=fristName+'_'+laetName
      },{immediate:true,deep:true})
    //immediate表示默认执行一次
    //deep表示深度监视
    ------------方法二
    const stop=watch(() => state.fristName, (val,oldval) => {
    	console.log(val);
   },{deep:true});
   
   //直接调用stop(),可以清除监听
   
   return {
      ...toRefs(state)
    };
}

watch监听多个属性

//监听reactive创造出来的数据使用箭头函数,ref直接放
 watch([() => state.fristName, () => state.laetName, fallName3], (val) => {
      console.log(val);
    });

watchEffect

//watchEffect不需要配置immediate,默认就会执行一次
// watchEffect: 监视所有回调中使用的数据
      watchEffect(()=>{
          fallName3.value= state.fristName+'_'+state.laetName
      })

vue2.0写法

  watch: {
    /**
     * 监听路由变化刷新页面
     */
    $route(to) {
      logger.log("watch router invoke", to.query);

      this.initPage();
    },
    configureList: {
      handler(newVale) {
        logger.log("watch configureList invoke", newVale);
      },
      deep: true,
      immediate: false,
    },
  },

4.computed

注意:计算属性如果只传入一个回调函数,表示的是get。

场景:三个input任意一个值变化,其他两个也会变化

<input type="text" v-model="state.fristName"/>
<input type="text" v-model="state.laetName"/>
<input type="text" v-model="fallName"/>

计算属性如果只传入一个回调函数,表示的是get。即fristName或laetName改变,fallName发生改变。但是fallName发生改变,其他两个值不会变化

 setup() {
    let state = reactive({
      fristName: "东方",
      laetName: "不败",
    });
    //fallName 返回的是一个ref对象
    const fallName = computed(() => {
      return state.fristName + "_" + state.laetName;
    });
  }

解决办法:

computed有不光有get,还有set

 const fallName = computed({
      get() {
        return state.fristName + "_" + state.laetName;
      },
      set(val: any) {
        const names = val.split("_");
        state.fristName = names[0];
        state.laetName = names[1];
      },
    });

5.生命周期

速懂vue3.0新特性及vue2.0区别_第5张图片

6. provide 和 inject(实现跨层级组件(祖孙)间通信),也可放在main.ts里面进行全局挂载使用

父组件

<template>
  <h1>父组件</h1>
  <p>当前颜色: {{color}}</p>
  <Son />
</template>
<script lang="ts">
import { provide, ref } from 'vue'
import Son from './Son.vue'
export default {
  name: 'ProvideInject',
  components: {
    Son
  },
  setup() {
    const color = ref('red')
    provide('color', color)
    return {
      color
    }
  }
}
</script>

子组件

<template>
    <h2>子组件</h2>
    <GrandSon />
</template>
<script lang="ts">
import GrandSon from './GrandSon.vue'
export default {
  components: {
    GrandSon
  },
}
</script>

孙组件

<template>
  <h3 :style="{color}">孙子组件: {{color}}</h3>
</template>
<script lang="ts">
import { inject } from 'vue'
export default {
  setup() {
    const color = inject('color')
    return {
      color
    }
  }
}
</script>

7.自定义hook函数(即把函数抽出来复用)

抽离前:

<template>
    <button @click="add">add</button>
    <img :src="src" alt="">
</template>
<script>
import {reactive, toRefs} from "vue";
export default {
  setup() {
   const state = reactive({
    	index: 1,
    	src:''
  });
  	const add = () => {
       console.log(state.index)
    	state.index++;
    	console.log(state.index)
  	};
    return {
      ...toRefs(state),
      add
    };
  },
};

抽离后:

<template>
    <button @click="add">add</button>
    <img :src="src" alt="">
</template>
<script>
import hander from './hooks/demo.ts'
import {toRefs} from "vue";
export default {
  setup() {
 	let {state,add}=hander()
    return {
      ...toRefs(state),
      add
    };
  },
};

demo.ts

import {reactive} from "vue";
export default function useMousePosition () {
	const state = reactive({
    		index: 1,
    		src:''
 	 });
  	const add = () => {
       	console.log(state.index)
    	state.index++;
    	console.log(state.index)
  	};
  	return {state,add}
}

8.defineAsyncComponent配合Suspense异步组件使用

<script  lang="ts">
import { defineComponent, defineAsyncComponent } from "vue";
// vue正常引入组件
import SuspensChild from '@/components/Suspense/Son.vue'
// vue2中动态引入组件的写法:(在vue3中这种写法不行)
const AsyncCompotent=()=>import('./Son.vue')
//vue3中动态引入组件
const SuspensChild = defineAsyncComponent(() => import("./Son.vue"));
</script>

注意:由于组件是异步引入的,会有一瞬间的空白,所以可以用Suspense配合loading填充,可以让我们创建一个平滑的用户体验

<template>
  <Suspense>
     //v-slot:default也可以写成#default
    <template v-slot:default><!-- 组件加载完后显示-->
      <SuspensChild/> <!-- 异步组件 -->
    </template>
    <template v-slot:fallback> <!-- 组件加载完前显示-->
      <h1>LOADING...</h1> <!-- LOADING的内容 -->
    </template>
  </Suspense>
</template>
<script  lang="ts">
import { defineComponent, defineAsyncComponent } from "vue";
const SuspensChild = defineAsyncComponent(() => import("./Son.vue"));
export default defineComponent({
  name: "Suspense1",
  components: {
    SuspensChild,
  },
  async setup(){}
});
</script>

9.新组件 Fragment及Teleport

Fragment

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

Teleport

Teleport 让组件的html在父组件界面外的特定标签(可能是body,也可能是其他)下插入显示

<template>
  <teleport to="body">  <!-- teleport 直接父级为body -->
    <div>
      <div>
        I'm a teleported modal! 
      </div>
    </div>
  </teleport>
</template>

速懂vue3.0新特性及vue2.0区别_第6张图片

10.customRef, readonly,shallowReactive,shallowRef, toRaw等

这些api在平常开发很少用到,这里我就不细讲了,有兴趣的朋友可以自行了解

11、全局挂载

速懂vue3.0新特性及vue2.0区别_第7张图片

三、setup语法糖,<script lang=“ts“ setup>

script-setup 的推出是为了让熟悉 3.0 的用户可以更高效率的开发组件,只需要给 script 标签添加一个 setup 属性,那么整个 script 就直接会变成 setup 函数,所有顶级变量、函数,均会自动暴露给模板使用(无需再一个个 return 了)。

ElementUI-plus等框架也是用的setup语法糖

如果你使用的是 TypeScript ,还需要借助 defineComponent 来帮助你对类型的自动推导,使用前:

<!-- 标准组件格式 -->
<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup () {
    // ...

    return {
      // ...
    }
  }
})
</script>

使用script-setup 后:

<!-- 使用 script-setup 格式 -->
<script setup lang="ts">
  // ...
</script>

注意:
在 script-setup 模式下,新增了 4 个全局编译器宏,他们无需 import 就可以直接使用。
但是默认的情况下直接使用,项目的 eslint 会提示你没有导入,
可以配置一下 eslint

// 项目根目录下的 .eslintrc.js
module.exports = {
  // 原来的lint规则,补充下面的globals...
  globals: {
    defineProps: 'readonly',
    defineEmits: 'readonly',
    defineExpose: 'readonly',
    withDefaults: 'readonly',
  },
}

使用setup语法糖后:

  1. 变量无需进行 return
  2. 子组件无需手动注册
  3. props 的接收方式变化为defineProps接收
  4. emits 的接收方式变化为defineEmits
  5. attrs 的接收方式变化为useAttrs
  6. 顶级 await 的支持
  7. 通过ref获取子组件的数据,需要子组件通过defineExpose暴露出来

1. 变量无需进行 return

<!-- 标准组件格式 -->
<template>
  <p>{{ msg }}</p>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup () {
    const msg: string = 'Hello World!';
    
    // 要给 template 用的数据需要 return 出来才可以
    return {
      msg
    }
  }
})
</script>

在 script-setup 模式下

<template>
  <div class="home">
    <div>加数:<input type="text" v-model="state.addNum1" /></div>
    <div>加数:{{ state.addNum2 }}</div>
    <div>和:{{ state.sum }}</div>
    <button @click="handleAddNum">=</button>
  </div>
</template>

<script lang="ts" setup>
import { reactive, provide, computed,ref } from "vue";

const state = reactive({
  addNum1: 1,
  addNum2: 1,
  sum: 0,
  nav: computed(() => store.state.home.nav),
});
const hellow=ref()
const msg: string = 'Hello World!';

const handleAddNum = () => {
  const { addNum1, addNum2 } = state;
  state.sum = Number(addNum1) + addNum2;
};
</script>

2. 子组件无需手动注册

<!-- 标准组件格式 -->
<template>
  <Child />
</template>

<script lang="ts">
import { defineComponent } from 'vue'

// 导入子组件
import Child from '..//Child.vue'

export default defineComponent({
  // 需要启用子组件作为模板
  components: {
    Child
  },

  // 组件里的业务代码
  setup () {
    // ...
  }
})
</script>

在 script-setup 模式下,只需要导入组件即可,编译器会自动识别并启用。

<!-- 使用 script-setup 格式 -->
<template>
  <Child />
</template>

<script setup lang="ts">
import Child from '@cp/Child.vue'
</script>

3. props 的接收方式变化

由于整个 script 都变成了一个大的 setup function ,没有了组件选项,也没有了 setup 入参,所以没办法和标准写法一样去接收 props 了。

这里需要使用一个全新的 API :defineProps

defineProps([
  'name',
  'userInfo',
  'tags'
])

如果 script 里的方法要拿到 props 的值

const props = defineProps([
  'name',
  'userInfo',
  'tags'
])

console.log(props.name);
const { tags} = toRefs(props)

props校验机制:

defineProps({
  name: {
    type: String,
    required: false,
    default: 'Petter'
  },
  userInfo: Object,
  tags: Array
});

或者使用ts校验

interface UserInfo {
  id: number;
  age: number;
}

defineProps<{
  nname?: string;
  tags: string[];
  userInfo: UserInfo;
}>();

4. emits 的接收方式变化

defineEmits 的用法和原来的 emits 选项差别不大

// 获取 emit
const emit = defineEmits(['chang-name']);

// 调用 emit
emit('chang-name', 'Tom');

5. attrs 的接收方式变化

attrs 和 props 很相似,也是基于父子通信的数据,如果父组件绑定下来的数据没有被指定为 props ,那么就会被挂到 attrs 这边来。

// 标准组件的写法
export default defineComponent({
  setup (props, { attrs }) {
    // attrs 是个对象,每个 Attribute 都是它的 key
    console.log(attrs.class);

    // 如果传下来的 Attribute 带有短横线,需要通过这种方式获取
    console.log(attrs['data-hash']);
  }
})

useAttrs 的基础用法

// 导入 useAttrs 组件
import { useAttrs } from 'vue'

// 获取 attrs
const attrs = useAttrs()

// attrs是个对象,和 props 一样,需要通过 key 来得到对应的单个 attr
console.log(attrs.msg);

6. ref、defineExpose

通过ref获取子组件的数据,需要子组件通过defineExpose暴露出来

标准组件写法里,子组件的数据都是默认隐式暴露给父组件的,也就是父组件可以通过 childComponent.value.foo 这样的方式直接操作子组件的数据

但在 script-setup 模式下,所有数据只是默认隐式 return 给 template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载 ref 变量获取子组件的数据。

在 script-setup 模式下,如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,这个操作,就是由 defineExpose 来完成。

子组件:

<script setup lang="ts">
// 定义一个想提供给父组件拿到的数据
const msg: string = 'Hello World!';

// 显示暴露的数据,才可以在父组件拿到
defineExpose({
  msg
});
</script>

然后你在父组件就可以通过挂载在子组件上的 ref 变量,去拿到暴露出来的数据了

<template>
  <div class="home">
    <HelloWorld ref="hellow" />
    <button @click="handleAddNum">=</button>
  </div>
</template>

<script lang="ts" setup>
import {ref } from "vue";
import HelloWorld from "@/components/HelloWorld.vue";
const hellow=ref()
const handleAddNum = () => {
  console.log('通过ref获取子组件defineExpose暴露的数据',hellow.value.msg2);
};

</script>

7.顶级 await 的支持

在 script-setup 模式下,不必再配合 async 就可以直接使用 await 了,这种情况下,组件的 setup 会自动变成 async setup 。

<script lang="ts">
<!-- 标准组件格式 -->
import { defineComponent, withAsyncContext } from 'vue'

export default defineComponent({
  async setup() {
    const post = await withAsyncContext(
      fetch(`/api/post/1`).then((r) => r.json())
    )

    return {
      post
    }
  }
})
</script>
<script setup lang="ts">
<!-- script-setup 模式下 -->
const post = await fetch(`/api/post/1`).then((r) => r.json())
</script>

四、比较Vue2与Vue3的响应式

vue2的响应式

  • 核心:
    1.对象: 通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视/拦截)
    2.数组: 通过重写数组更新数组一系列更新元素的方法来实现元素修改的劫持
		let obj = {}
        //  1.要操作的对象
        //  2.要操作的属性
        //  3.具体值
        //数据劫持
        Object.defineProperty(obj, 'username', {
            get: function () {
                console.log('取值')
            },
            set: function (val) {
                console.log('赋值')
            },
        })
  • 问题:
    1.需要响应化的数据较大,递归遍历性能不好、消耗较大(defineProperty只对当前这一个属性进行监听,所以需要递归遍历每一个属性值。)
    2.新增或删除属性无法监听,对象直接新添加的属性或删除已有属性, 界面不会自动更新,直接通过下标替换元素或更新length, 界面不会自动更新
    3.defineProperty只对当前这一个属性进行监听,所以需要递归遍历每一个属性值。Proxy 的监听是针对一个对象的,那么对这个对象的所有操作会进入监听
    操作,可以代理所有属性

vue3的响应式

  • 核心:
    1.通过Proxy(代理): 拦截对data任意属性的任意(13种)操作, 包括属性值的读写, 属性的添加, 属性的删除等…
    2.通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作
		//目标对象
        let obj = {
            name: "tom",
            age: 25,
            wife: {
                name: "marry",
                age: 22,
            },
        }
        //把目标对象变成代理对象
        //参数1:obj-->目标对象;参数2:handler-->处理器对象,用来监视数据,及数据的操作;
        const proxyUser = new Proxy(obj, {//
            //get获取目标对象的某个属性值
            get(target, prop) {
                console.log('get')
                //这里要通过 Reflect反射返回,否则proxyUser.name是undefiend
                return Reflect.get(target, prop)
            },
            //set方法不仅能修改还能为目标对象增加属性值
            set(target, prop, newval) {
                console.log('set')
                return Reflect.set(target, prop, newval)
            },
            //deleteProperty删除目标对象的某个属性值
            deleteProperty(target, prop) {
                console.log('deleteProperty')
                return Reflect.deleteProperty(target, prop)
            },
        })
        ---
        注意:直接操作目标对象,视图是不会跟新的
        ---
        //-----获取属性值测试
        console.log('结果=>', proxyUser.name);
        //-----更改属性值测试
        proxyUser.name = '小明'
        //-----增加属性值测试
        proxyUser.sax = '男'
        //-----删除属性值测试
        delete proxyUser.name
        //-----更改深层次属性值测试
        proxyUser.wife.name='小红'

五、vue3使用vuex,vue-router

<template>
  <div class="home">
    <button @click="alter">路由</button>
  </div>
</template>

<script>
import {defineComponent} from "vue";
import { useRouter, useRoute,onBeforeRouteLeave } from "vue-router";
//守卫beforeRouteEnter,在composition api中被移除了,解决办法
//1、可以通过watch监听路由实现
//2、beforeRouteEnter不需要导入,只需要写在setup外即可
import { useStore } from "vuex";
export default {
  name: "Home",
  beforeRouteEnter(to,from,next){
    next(vm=>{
      console.log('组件内的守卫===',vm)
    })
  },
  setup() {
    let router = useRouter();//路由实例
    let route = useRoute()//路由信息,query,params等
    let store = useStore();

    const alter = () => {
      console.log(store.state.num);
    };
    onBeforeRouteLeave((to,from,next) => {
		next()
	});
		
    //监听路由变化
    watch(route,(val)=>{
      console.log('watch',val.matched)
    },{immediate:true,deep:true})
    
    const routerto = () => {
      router.push({
        path: "/about",
        query: {
          id: 2,
        },
      });
    };
    return {

    };
  },
};
</script>

在这里插入图片描述

六、简单总结

数据监听方式变成了Proxy,消除了Object.defineProperty现有的限制(例如无法检测新的属性添加),并提供更好的性能。

vue3解决了vue2的一些问题,大型应用的性能问题、ts支持不友好问题,自定义渲染API解决体系架构存在的问题,Compostion API让代码的组织形式更好。vite开发构建工具让开发体验更好,Tree shaking让包更小、性能更优。

总的来说vue3还是非常棒的,带来了很多非常好的新特性。

你可能感兴趣的:(vue3.0,vue,vue3.0,typescript,ts,vuex)