vue3.0学习记录

1、优化点

相较vue2.0,vue3.0主要有以下变化
1、性能优化
打包体积减少约40%,首次渲染速度减少50%,更新渲染速度减少130%,内存占用减少约50%
2、使用proxy代替defineProperty实现响应式
3、更好的支持ts
4、优化生命周期,增加setup,ref,reactive等新的概念

2、composition API

1、setup
组件中所用到的:数据、方法等等,均要配置在setup中。
setup函数的两种返回值:
若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。
若返回一个渲染函数:则可以自定义渲染内容。
2、ref,reactive
都能实现响应式,但是ref操作时需要通过.value,略微复杂;注意reactive不能实现基础数据类型的响应式,会报错。ref对于基础类型的响应式使用getter和setter实现,复杂类型会调用reactive实现

<template>
  <div>
    {{ author }}
  </div>
  <el-button @click="changeAuthor">测试</el-button>
  <div>
    {{ author1.name }}
    {{ author1.hobbies }}
    {{ author1.parent }}
  </div>
  <el-button @click="changeAuthor1">测试</el-button>
  <div>
    {{ person.name }}
    {{ person.hobbies }}
    {{ person.parent }}
  </div>
  <el-button @click="changePerson">测试</el-button>
  <div>
    {{ test1 }}
  </div>
  <el-button @click="changeTest">测试</el-button>
</template>
<script>
import { reactive, ref } from "vue";
export default {
  name: "List",
  components: {},
  setup(props) {
    //直接定义无法实现响应式
    // let author = 'a1'
    // function changeAuthor(){
    //   console.log(1111)
    //   author = 'a2'
    // }
    // return {author,changeAuthor}

    //使用ref定义基础类型实现响应式
    let author = ref("a1");
    function changeAuthor() {
      author.value = "a2";
    }

    //使用ref实现对象、数组响应式
    let author1 = ref({
      name: "a",
      age: 21,
      hobbies: ["swimming", "running"],
      parent: {
        mom: "a1",
        fath: "a2",
      },
    });
    function changeAuthor1() {
      author1.value.name = "b";
      author1.value.hobbies[0] = "pingpang";
      author1.value.parent.mom = "b1";
    }

    //使用reactive实现对象、数组响应式
    let person = reactive({
      name: "a",
      hobbies: ["swimming", "running"],
      parent: {
        mom: "a1",
        fath: "a2",
      },
    });
    function changePerson() {
      person.name = "b";
      person.hobbies[0] = "pingpang";
      person.parent.mom = "b1";
    }

    //注意,不能使用reactive定义基础类型,改变值时控制台会报错,如下图所示
    let test1 = reactive("aaa");
    function changeTest() {
      test1 = "bbb";
    }
    return {
      author,
      changeAuthor,
      person,
      changePerson,
      test1,
      changeTest,
      author1,
      changeAuthor1,
    };
  },
};
</script>

<style>
</style>

使用reactive定义基础类型,改变值时控制台会报错在这里插入图片描述
3、vue3中的响应式原理
使用proxy实现

    let person = {
      name: "a",
      hobbies: ["swimming", "running"],
      parent: {
        mom: "a1",
        fath: "a2",
      },
    }

    let p = new Proxy(person, {
      get(target, propName) {
        return Reflect.get(target, propName);
      },
      set(target, propName, value) {
        return Reflect.set(target, propName, value);
      },
      deleteProperty(target, propName) {
        return Reflect.deleteProperty(target, propName);
      },
    });

4、watch,cumputed,watchEffect

    //计算属性简写
    // let hobbies = computed(() => {
    //   return person.hobbies.join(",");
    // });
    //计算属性完整写法
    let hobbies = computed({
      get() {
        return person.hobbies.join(",");
      },
      set(value) {
        person.hobbies = value.split(",");
      },
    });
    //使用ref定义基础类型实现响应式
    let author = ref("a1");
    function changeAuthor() {
      author.value = "a2";
    }
    //使用reactive实现对象、数组响应式
    let person = reactive({
      name: "a",
      hobbies: ["swimming", "running"],
      parent: {
        mom: "a1",
        fath: "a2",
      },
    });
    function changePerson() {
      person.name = "b";
      person.hobbies[0] = "pingpang";
      person.parent.mom = "b1";
    }

    watch(()=>author1.value.name,(newVal,oldVal)=>{
      console.log(newVal)
      console.log(oldVal)
    })

    watch(author,(newVal,oldVal)=>{
      console.log(newVal)
      console.log(oldVal)
    })


    //若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue,且强制开启了深度监视
    watch(person,(newVal,oldVal)=>{
      console.log(newVal)
      console.log(oldVal)
    })
    //监视某个特定属性
     watch(()=>person.name,(newVal,oldVal)=>{
      console.log(newVal)
      console.log(oldVal)
    })
    //不指定监听对象,回调函数中使用哪个变量则监听哪个变量,很方便,类似于computed,但无需返回值
    watchEffect(() => {
      let a = person.name
      console.log('person.name更新了');
    });

5、生命周期
与vue2相比,destoryed和beforeDestory没了,变成unmounted和beforeUnmount,setup在beforeCreate之前调用一次
beforeCreate==》setup
created==》setup
beforeMount==》onBeforeMount
mounted==》onMounted
beforeUpdate==》onBeforeUpdate
updated==》onUpdated
beforeDestory==》onBeforeUnmount
destoryed==》onUnmounted

<template>
<div>{{name}}</div>
<el-button @click="changeName"></el-button>
</template>
<script>
import { onBeforeMount, onMounted, onBeforeUnmount, onUnmounted,onBeforeUpdate,onUpdated,ref } from "vue";
export default {
  name: "List",
  components: {},
  beforeCreate() {
    console.log("beforeCreate");
  },
  created() {
    console.log("created");
  },
  beforeMount() {
    console.log("beforeMount");
  },
  mounted() {
    console.log("mounted");
  },
  beforeUpdate(){
    console.log("beforeUpdate");
  },
  updated(){
    console.log("updated");
  },
   // vue2中的 beforeDestroy与 destroyed已经改名 无法使用
  beforeUnmount() {
    console.log("vue2 中的生命周期 beforeDestroy(beforeUnmount)");
  },
  unmounted() {
    console.log("vue2 中的生命周期 destroyed(unmounted)");
  },
  setup(props) {
      let name = ref('a')
      function changeName(){
          name.value='b'
      }
    console.log("setup");
    onBeforeMount(() => {
      console.log("onBeforeMount");
    });
    onMounted(() => {
      console.log("onMounted");
    });
    onBeforeUpdate(() => {
      console.log("onBeforeUpdate");
    });
    onUpdated(() => {
      console.log("onUpdated");
    });
    onBeforeUnmount(() => {
      console.log("onBeforeUnmount");
    });
    onUnmounted(() => {
      console.log("onUnmounted");
    });
    return {name,changeName}
  },
};
</script>

在这里插入图片描述
可以看出setup执行于beforeCreate之前,同类型的钩子函数,vue3中的先执行
6、hook
类似于vue2中的mixin的使用方式,可以将部分代码抽离封装,需要时引入使用,使用import引用
7、toRef,toRefs
toRef创建对象的引用,修改会影响原始值

// let person = reactive({
    //     name:'a',
    //     parents:{
    //         m:'a1',
    //         f:'a2'
    //     }
    // })
    let person = {
        name:'a',
        parents:{
            m:'a1',
            f:'a2'
        }
    }
    let name1=toRef(person,'name')
    console.log('####',name1)

	// const x = toRefs(person)
	// console.log('******',x)
    function changeName(){
        person.name = 'aa'
        console.log('name1.value',name1.value) //'aa',但视图不更新,使用reactive响应式定义时视图会更新
        console.log('person.name',person.name) //'aa',但视图不更新,使用reactive响应式定义时视图会更新
    }
    function changeName1(){
        name1.value = 'bb'
        console.log('name1.value',name1.value)//'bb',但视图不更新,
        console.log('person.name',person.name)//'bb',但视图不更新,
    }
    return {person,name1,changeName,changeName1}

8.readonly和shallowReadonly
把响应式数据变为只读,shallowReadonly只保证第一层

 let person = reactive({
      name: "a",
      p: {
        m: "a1",
        f: "a2",
      },
    });
    let person1 = readonly(person);
    let person2 = shallowReadonly(person);
    function changeName() {
      person1.name = "b";
      person1.p.m = "b1";
      console.log("readonly", person1);

      person2.name = "b";
      person2.p.m = "b1";
      console.log("shallowReadonly", person2);
    }
    return { person, person1, changeName };

下图中person1改变是因为person发生变化导致person原对象发生了变化,可知,改变原person对象也会影响值
在这里插入图片描述
8、toRow,markRow
toRow将一个响应式对象转换为非响应式。
markRow标记一个普通对象后,该对象不能再创建响应式对象;对响应式对象不起作用;有些值不应被设置为响应式的,例如复杂的第三方类库等。当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。

      let oriPerson = {
      name: "a",
      p: {
        m: "a1",
        f: "a2",
      },
    }
    oriPerson = markRaw(oriPerson)
    let person = reactive(oriPerson);
    //person的变化不会再引起页面的变化

9、shallowReactive和shallowRef
shallowReactive只处理第一层数据, 发现一个问题,如果同时更新了第一层属性和第二层属性,则深层属性也可以实现视图刷新,因为第一层属性更新的时候会触发视图的更新,单独更新则不行
shallowRef只能将基础类型转换为响应式,如shallowRef(0)

let oriPerson = {
      name: "a",
      p: {
        m: 'a1',
        f: "a2",
      },
    }
    let person = shallowReactive(oriPerson);
    function changeName() {
      person.name = "b"; 
      person.p.m = {nn:1};
      console.log("markRaw", person);
    }

10、customRef
自定义ref,可以实现防抖。之前一直搞不太懂防抖和节流区别今天看了一篇文章,防抖就是一个行为暂停一段时间才触发,节流是一个行为一直操作,一段时间触发一次时间,不等该行为停止。

function myRef(value, delay) {
      let timer;
      return customRef((track, trigger) => {
        return {
          get() {
            track();
            return value;
          },
          set(val) {
            if (timer) {
              clearTimeout(timer);
            }
            timer = setTimeout(() => {
              value = val;
              trigger();
            },delay);
          },
        };
      });
    }
    let a = myRef(10,3000);
    function changeA(){
        a.value = 20
    }

11、teleport,fragment,suspense
teleport类似于穿梭框,可以将不属于该组件的元素穿梭到指定元素

  //list组件
  <teleport to="#aa">
    <div>teleport</div>
  </teleport>
  //list父组件
 <el-button @click="showList = !showList">切换组件</el-button>
  <div id = 'aa'></div> //最终teleport内的元素会渲染到此处
  <list v-if="showList"></list>

在这里插入图片描述
fragment虚拟dom元素,不会真的渲染,可以实现在template中不用唯一根元素的功能
suspense异步组件未加载之前显示的内容


  <Suspense v-if="showList">
    <template v-slot:default>
      <list />
    </template>
    <template v-slot:fallback>
      <h3>加载中.....</h3>
    </template>
  </Suspense>
import { defineAsyncComponent } from "vue";
const list = defineAsyncComponent(
  {
    loader:() => import("./components/list.vue"),
    delay:5000
  }
);

12、其他改变
(1)全局API Vue=>app
(2)去除过滤器,移除keycode作为修饰符,去除$on,$off,$once等事件支持

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值