vue2.0与3.0的区别

1. vue2和vue3双向数据绑定原理发生了改变

  1. vue2 的双向数据绑定是利用ES5 的一个 APIObject.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。
  2. vue3 中使用了 es6 的 ProxyAPI 对数据代理。

相比于vue2.x,使用proxy的优势如下
defineProperty只能监听某个属性,不能对全对象监听
可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数 组内部数据的变化

2.在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 }
  }
}

3.默认项目目录结构也发生了变化:

  1. 移除了配置文件目录,config 和 build 文件夹
  2. 移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public 中
  3. 在 src 文件夹中新增了 views 文件夹,用于分类 视图组件 和 公共组件

4. 2.0和3.0的生命周期对比

2.0生命周期3.0生命周期
beforeCreate(组件创建之前)setup(组件创建之前)
created(组件创建完成)setup(组件创建完成)
beforeMount(组件挂载之前)onBeforMount(组件挂载之前)
mounted(组件挂载完成)onMounted(组件挂载完成)
beforeUpdate(数据更新,虚拟DOM打补丁之前)onBeforeUpdate(数据更新,虚拟DOM打补丁之前)
updated(数据更新,虚拟DOM渲染完成)onUpdated(数据更新,虚拟DOM渲染完成)
beforeDestroy(组件销毁之前)onBeforeUnmount(组件销毁之前)
destroyed(组件销毁之后)onUnmounted(组件销毁之后)

5.vue3特点

Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
作用: 聚合代码 & 逻辑重用

6.知识点

  1. 使用defineComponent 构建应用及绑定事件
  2. 使用setup(props,content)父子通信
  3. 使用 reactive 绑定数据
  4. 使用 ref ( torefs ) 绑定数据
  5. 使用 getCurrentInstance 获取当前实例化对象上下文信息
  6. watch、watchEffect 数据监听

1.使用 reactive 绑定数据

<template>
  <div>
    <h1>使用 reactive 绑定数据</h1>
    <p>{{state.msg}}</p>
    <p>{{info}}</p>
    <p>
      <button @click="changeMsg">changeMsg</button>
    </p>
  </div>
</template>
<script>

// Hooks 编程,在 vue 中导入对应的函数方法,面向函数式进行编程
// Vue-composition-API 这里就是Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)

import { defineComponent, reactive } from "vue";
export default defineComponent({
  name: 'test1',
  setup() {  // setup钩子函数
    // 使用响应式函数reactive构建proxy响应式对象state
    const state = reactive({
      msg: '时光'
    })
    console.log(state); // state对象是一个proxy拦截对象
    let info = 'hello'; // info是一个普通对象,修改后不会被proxy拦截,进而页面也不会动态更新
    const changeMsg = () => { // 在外边定义methods
      state.msg = '时光,你好'
      info = 'hello,你好'
    }
    return {  // 使用时,要把对象return出去,才能在template中使用
      state,
      info,
      changeMsg
    }
  }
})
</script>

2. setup()函数 完成父子通信

*setup(props)第一个参数props*

setup函数接收props作为其第一个参数,props对象是响应式的(单向的父—>子),watchEffect或watch会观察和响应props的更新。不要对props对象进行解构,那样会失去响应性。在开发过程中,props对象对用户空间代码时不可变的,用户尝试修改props时会触发警告。

案例1:props作为setup的第一个参数

// 父组件 Home.vue
<template>
  <div class="home">
    <About :name="sendData"/>
  </div>
</template>
<script>
  import {ref} from 'vue'; 
  import About from './About'
  export default{
    components:{
      About,
    },
    setup(){
      const sendData = ref('这世界很酷');
      return {
        sendData
      }
    }
  }
</script>

// 子组件About.vue
<template>
  <div class="about">
  {{propContent}}
  </div>
</template>
<script>
  import {watchEffect} from 'vue';
  export default{
    props:{
      name:String
    },
    setup(props){
      let propContent;
      watchEffect(()=>{
        propContent = props.name
      })
      return {
        propContent
      }
    }
  }
</script>

2. setup(props,context)第二个参数Context上下文对象

// 父组件 Home.vue
<template>
  <div class="home">
    <About :name="sendData.val" @name-changed=changeName>
      世界变化不停,人潮川流不息
    </About>
  </div>
</template>
<script>
  import {reactive} from 'vue';
  import About from './About';
  export default{
    components:{
      About,
    },
    setup(){
      const sendData = reactive({
        val:'sendData'
      })

      setTimeout(()=>{
        sendData.val+=1;
      },1000)

      function changeName(){
        console.log("事件传送出来了")
      }
      return {
        sendData,
        changeName,
      }
    }
  }
</script>

//子组件 About.vue
<template>
  <div class="about">
    
  </div>
</template>
<script>
  import {watch} from 'vue';
  export default {
    props:{
      name:String
    },
    setup(props, context) {
      console.log(context,"上下文");
      watch(()=>props.name,(newName,oldName)=>{
        console.log(newName,oldName);
        context.emit('name-changed');//相当于this.$emit()
      }
    );
    },
  }
</script>

3.使用 ref(toRefs) 绑定数据

<template>
  <div>
    <p>使用v-model双向数据绑定的数据内容是:{{ msg }}</p>
    <p>
      <!-- 自己实现双向数据绑定,监听input事件,动态修改nmsg的值 -->
      <input type="text" ref="myInput" @input="input" :value="nmsg" />
    </p>
    <p>使用@input事件动态实现双向数据绑定的数据内容是:{{ nmsg }}</p>
    <p>
      <!-- 使用ref方法动态定义并双向绑定hmsg -->
      <input type="text" v-model="hmsg" @input="hmagInpu" />
    </p>
    <p>使用ref方法动态定义并双向数据绑定的数据hmsg是:{{ hmsg }}</p>
    <p>toRefs 来实现在模板中不需要追加 state 调用数据:{{ msg }}</p>
  </div>
</template>
<script>
import {
  defineComponent,
  reactive,
  getCurrentInstance,
  toRefs,
  ref,
  computed,
} from "vue";

export default defineComponent({
  setup() {
    const state = reactive({
      msg: "",
      nmsg: "",
      cmsg: computed(() => {
        // 1.计算属性
        return state.msg.length;
      }),
    });

    // 2.可以使用getCurrentInstance hook 来拿到当前实例化对象上下文信息,但是除非极其特殊的情况,否则不建议这样使用
    const { ctx } = getCurrentInstance();
    const input = () => {
      // 在vue3中,因为是面向hooks函数编程,所以,无法通过this拿到当前vue实例化对象
      console.log(ctx.$refs.myInput.value); // 像使用vue2中的this一样,使用ctx(上下文内容信息)
      state.nmsg = ctx.$refs.myInput.value;
    };

    // 3.使用ref方法来定义一个响应式监听的对象,在实际开发中我们都是用这种方法来构建响应式对象
    const hmsg = ref("abc");
    const hmagInpu = () => {
      // 在内部使用hmsg的值,需要使用value来获取对应的值
      console.log("获取到的hmsg值是:" + hmsg.value);
    };

    return {
      // 4.使用toRefs hook方法方便,访问msg不需要使用state.msg,直接msg就可以获取到
      ...toRefs(state),
      hmsg,
      input,
      hmagInpu,
    };
  },
});
</script>

总结
1.reactive

1…reactive方法,直接传入一个对象 state ,这个对象就是 proxy 拦截的对象
2.然后再把这个 state 对象直接 return 出去就能被调用
3.在 temolate 中使用 state.msg 来访问
4.在 js 中也使用 state.msg 来访问

2.ref

1.使用 ref 直接声明一个 proxy 响应式对象 msg
2.然后把这个 msg 对象直接 return 出去
3.在 template 中直接使用 {{msg}}
4.注意:在 js 中需要使用 msg.value

3.watch、watchEffect 数据监听

<template>
  <div>
    <h1>watch、watchEffect 数据监听</h1>
    <p>{{ msg }}</p>
    <p>{{ msg2 }}</p>
    <p>{{ info }}</p>
    <p>
      <button @click="changeMsg">changeMsg</button>
    </p>
    <p>
      <button @click="changeMsg2">changeMsg2</button>
    </p>
  </div>
</template>
<script>
import { defineComponent, reactive, watchEffect, watch, toRefs } from "vue";

export default defineComponent({
  name: "watch",
  // setup钩子函数
  setup() {
    // 使用响应式函数reactive构建proxy响应式对象state
    const state = reactive({
      msg: "时光",
      msg2: "kity",
      changeMsg2: () => {
        state.msg2 = "kity,你好";
      },
    });
    const changeMsg = () => {
      // 在外边定义methods
      state.msg = "时光,改变";
      info = "hello,改变";
    };
    let info = "hello";
    // watch监听只能是 getter/effect 函数、ref、reactive对象或数组
    // 简单监听
    watch(state, () => {
      console.log("观察整个state中属性变化", state.msg); // 只要state中的值有变化,就会打印
    });
    // 监听指定的信息
    watch(
      () => state.msg,
      (newVal, oldVal) => {
        console.log("01-msg的新值是:" + newVal + "-------旧值是:" + oldVal);
      }
    );
    // 监听多个属性(数组形式)
    watch([() => state.msg, () => state.msg2], (newVal, oldVal) => {
      console.log("02-msg的新值是:" + newVal + "-------旧值是:" + oldVal); // 02-msg的新值是:时光,你好,俞亮-------旧值是:时光,俞亮
    });
    // 不需要指定监听的属性
    watchEffect(() => {
      // 程序运行时,初始化就会执行一次,完成监听准备工作
      console.log("03-watchEffect监听 state 中数据变化:", state.msg); // 有点像computed计算属性,用到的数据发生改变才会执行
    });

    // 使用时,要把对象return出去,才能在template中使用
    return {
      ...toRefs(state),
      info,
      changeMsg,
    };
  },
});
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值