vue3.0与2.0区别

131 阅读6分钟

1. Template  fragments碎片

组件可以拥有多个根节点,解决多个div嵌套问题

2.数据获取

Vue3的数据获取在反应数据(Reactive Data)中,通常包含在一个反应状态(Reactive State)变量中。(reactive的作用是将对象包装成响应式对象,通过Proxy代理后的对象。)

响应式原理: Proxy代理拦截:reactive函数执行,会将传入的target对象通过Proxy包装,拦截它的get,set等,并将代理的target缓存。(组件在render阶段,视图会读取数据对象上的值进行渲染,此时便触发了Proxy的get,由此触发对应的track函数,记录下了对应的ReactiveEffect,也就是常说的依赖收集。)

1).Ref与reactive区别:

reactive 和 ref 都是用来定义响应式数据的, reactive更推荐去定义复杂的数据类型, ref 更推荐定义基本类型,ref 和 reactive 本质我们可以简单的理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value。(ref定义基本数据类型,ref也可以定义数组和对象)

2).判断数据到底是ref还是reactive?

通过isRef / isReactive 方法,对当前数据的__v_ref来判断的,如果有这个私有的属性, 并且取值为true, 那么就代表是一个ref类型的数据

3.响应式数据

Vue3.0,我们就需要使用一个新的setup() 方法,此方法在组件初始化构造的时候触发。

使用以下三步来建立反应性数据:

1)从vue引入reactive

2)使用reactive()方法来声名我们的数据为反应性数据

3)使用setup()方法来返回我们的反应性数据,从而template可以获取这些反应性数据

import { reactive } from 'vue'
export default {
  props: {
    title: String
  },
  setup () {
    const state = reactive({
      username: '',
      password: ''
    })
 
    return { state }
}}

这里构造的反应性数据就可以被template使用,可以通过state.username和state.password获得数据的值,需要先声名一个方法然后在setup()方法中返回(return), 在组件内就可以调用这个方法了。

4.methods方法

Vue3 的合成型API里面的setup()方法也是可以用来操控methods的。创建声名方法其实和声名数据状态是一样的。需要先声名一个方法然后在setup()方法中返回(return), 这样组件内就可以调用这个方法了。

export default {
  props: {
    title: String
  },
  setup () {
    const state = reactive({
      username: '',
      password: ''
    })
 
    const login = () => {
      // 登陆方法    }
    return { 
      login,
      state
    }
  }}

5.生命周期钩子

现在 Vue3 的合成型API里面的setup()方法可以包含了基本所有东西。生命周期的钩子就是其中之一!但是在 Vue3 生周期钩子不是全局可调用的了,需要另外从vue中引入,生命周期的挂载钩子叫onMounted,引入后我们就可以在setup()方法里面使用onMounted挂载的钩子了。(与2.0生命周期相似,在前面加了on,setup这个生命周期发生在beforeCreate和created之前,此时无法访问data、computed、methods、refs )

6.计算属性 - Computed Properties

Vue3 的设计模式给予开发者们按需引入需要使用的依赖包,在 Vue3 使用计算属性,需要在组件内引入computed。使用方式就和反应性数据(reactive data)一样,在state中加入一个计算属性。(计算属性可以写在声明的响应式变量内,也可单独声明使用)

 setup () {
    const state = reactive({
      username: '',
      password: '',
      lowerCaseUsername: computed(() => state.username.toLowerCase())
    })
 
 const twiceTheCounter = computed(() => counter.value * 2)

7.模板引用

为了获得对模板内元素或组件实例的引用,一样声明 ref 并从 setup() 返回:

<template> 
  <div ref="root">This is a root element</div></template>
<script>
  import { ref, onMounted } from 'vue'
  export default {
    setup() {
      const root = ref(null)
      onMounted(() => {
        // DOM 元素将在初始渲染后分配给 ref
        console.log(root.value) // <div>This is a root element</div>
      })
      return {
        root }
}}
</script>

这里在渲染上下文中暴露root,并通过ref=”root”,将其绑定到div作为其ref。(在虚拟dom补丁算法中,若Vnode的ref键对应于渲染上下文中的 ref,则 VNode 的相应元素或组件实例将被分配给该 ref 的值。这是在虚拟 DOM 挂载/打补丁过程中执行的,因此模板引用只会在初始渲染之后获得赋值,即在onMounted生命周期中)

8.watch监听

使用从 Vue 导入的 watch 函数执行相同的操作。它接受 3 个参数:

  1. 一个想要侦听的响应式引用或 getter 函数
  2. 一个回调
  3. 可选的配置选项
import {  watch } from 'vue'
//一个变量
const counter = ref(0)
//监听函数 watch(监听的值,回调,可选的配置选项)
watch(counter, (newValue, oldValue) => {
  console.log('The new counter value is: ' + counter.value)
})

注意:侦听模板引用的变更可以替代前面例子中演示使用的生命周期钩子。

9.Mixin

Mixin 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个 mixin 对象可以包含任意组件选项。当组件使用 mixin 对象时,所有 mixin 对象的选项将被“混合”进入该组件本身的选项。

局部mixins的配置:

  export const mixin1 = {
	methods: {
		showName(){
			alert('第一个mixin')
		}
	},
	mounted() {
		console.log('你好啊!')
	},}
export const mixin2 = {
	data() {
		return {
			sum:100
		}
	},
   methods: {
		showName(){
			alert('第二个mixin')
		}
	},
}
<script>
	import {mixin1,mixin2} from '../mixin'
 
	export default {
		name:'Student',
		data() {
			return {
				name:'张三',
				
			}
		},
		mixins:[mixin1,mixin2]
	}
</script>

全局注册:全局mixins 对vm,和所有vm均进行mixins

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
import {mixin1,mixin2} from '../mixin'
//关闭Vue的生产提示
Vue.config.productionTip = false
Vue.mixin(mixin1)
Vue.mixin(mixin2)
//创建vm
new Vue({
	el:'#app',
	render: h => h(App)
})

10.自定义组件

除了核心功能默认内置的指令 (例如 v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

举个聚焦输入框的例子,如下:

//全局注册
const app = Vue.createApp({})// 注册一个全局自定义指令 `v-focus`
app.directive('focus', {
  // 当被绑定的元素挂载到 DOM 中时……
  mounted(el) {
    // 聚焦元素
    el.focus()
  }})
注册局部指令:
directives: {
  focus: {
    // 指令的定义
    mounted(el) {
      el.focus()
    }
  }}
 
注册局部指令:
directives: {
  focus: {
    // 指令的定义
    mounted(el) {
      el.focus()
    }
  }}
  使用方式:<input v-focus />
使用方式 <input v-focus />

11. 路由变化

传参和原来一样,取参发生改变:

Params传参:
<router-link to="/home/111">点击跳转到home页面并传参</router-link>
 vue3.0import { useRoute } from 'vue-router'
    const route = useRoute()
console.log(route.params.id);//111
query传参:
 <router-link to="/test?id=999">test</router-link>
    //接受的时候
  import { useRoute } from 'vue-router'
    const route = useRoute()
    console.log(route.query.id);//999
Js传参方式:
import { useRouter } from 'vue-router'
    const route = useRouter()
            route.push({
                path:"/lianxi",
                query:{
                    id:666
                }
            });
             route.push({
                name:'lianxi',
                params:{
                    id:666
                }
            });
   import { useRoute } from 'vue-router'
   const route = useRoute()
   console.log(route.query.id);

12.总结

现在基本都看到vue2与vue3其实概念与理念都是一样的。只是有一些属性获取方式和声名和定义方式稍微变了。总结一下,我觉得 Vue3 给我们前端开发者带来了全新的开发体验,更好的使用弹性,可控度也得到了大大的提升。全新的合成式API(Composition API)可以提升代码的解耦程度 —— 特别是大型的前端应用,效果会更加明显。还有就是按需引用的有了更细微的可控性,让项目的性能和打包大小有更好的控制。

案例项目代码整理:

<template>
  <div class='form-element'>
    <h2> {{ state.title }} </h2>
    <input type='text' v-model='state.username' placeholder='Username' />
    
    <input type='password' v-model='state.password' placeholder='Password' />
 
    <button @click='login'>
      Submit
    </button>
    <p> 
      Values: {{ state.username + ' ' + state.password }}
    </p>
  </div></template>
<script>
import { reactive, onMounted, computed } from 'vue'
export default {
  props: {
    title: String
  },
//方法在组件初始化构造的时候触发,可以直接使用vue3的反应api,返回我们的反应性数据,从而template可以获取这些反应性数据
 //setup()方法可以接收两个参数:
   //props - 不可变的组件参数
//context - Vue3 暴露出来的属性(emit,slots,attrs)
 
 //props接收传的参数,emit是事件触发
   setup(props, { emit }) {
//reactive是反应数据是包含在一个反应状态(reactive state)变量中
    const state = reactive({
      username: '',
      password: '',
     //计算属性:在state中加入一个计算属性:
      lowerCaseUsername: computed(() => state.username.toLowerCase())
    })
 
    onMounted(() => {
      console.log('title: ' + props.title)
    })
//先声名一个方法然后在setup()方法中返回(return)
    const login = () => {
      emit('login', {
        username: state.username,
        password: state.password
      })
    }
 
    return { 
      login,
      state
    }
  }}</script>