vue3.0

文章详细对比了vite和vuecli在创建项目时的差异,强调了vite的快速启动和模块热更新优势。同时,介绍了Vue2的optionsAPI与Vue3的CompositionAPI,特别是setup函数的使用和响应式数据处理(ref,reactive,toRefs)。文章还涵盖了组件通信、生命周期、路由、Vuex以及自定义hooks函数的概念和用法。
摘要由CSDN通过智能技术生成

创建项目

* vue cli创建    ==> vue create 项目名称
* vite创建  ===> npm init vite-app 项目名称

vite优势

1。快速冷启动 vite先启动服务,,根据客户端的请求加载不同的模块处理,实现按需加载 冷启动时不会打包全部项目文件代码。
webpack则是,一开始就先分析分析各个模块之间的依赖将整个项目都打包一遍,再开启dev-server,如果项目规模庞大,模块太多,打包时间必然很长,会造成打包的bundle体积很大,热更新速度很慢。
2.模块热更新:采用立即编译当前修改文件的办法,让浏览器重新请求该模块即可,同时结合vite的缓存机制(http缓存 ==》 Vite内置缓存),加载更新后的文件内容。不像webpack那样需要把该模块的相关依赖模块全部编译一次
3.打包编译速度快 使用esbuild预构建依赖,而esbuild是用Go编写的,go比JS编写的打包器快很多

vue2 options api / vue3 组合式 API

vue2 options api(computed ,data,methods) 约定了该在哪个位置做什么事,这在一定程度上也强制我们进行了代码分割,大型组件中,数据与方法会很多,必须不断地在选项代码块之间“跳转”,以找到与该关注点相关的部分,理解和维护复杂组件变得困难
Composition API提供了一个setup函数,我们可以将data数据、计算属性、方法等等,都放在setup函数中,这样就可以对业务进行集中处理了

setup

  • 在beforeCreate之前执行。beforeCreate有this,但是获取不到data的值,所以setup 中是不能使用 this 的,
  • 在vue2的配置中可读取到vue3配置中的属性和方法
  • 组合式 API 入口点 它会在Vue实例创建完成前被调用。所以,setup函数中没有this指针undefined 但是getCurrentInstance可以替代this但不推荐
  • 只能同步使用setup函数,不能用async将其设为异步。
  • 如果 setup 返回一个对象,则对象的属性将会被合并到组件模板的渲染上下文,我们就可以在模板里使用对应的属性和方法

setup语法糖

<script setup lang="ts"></script>
  • setup语法糖就可以不用写setup函数了。并且,数据和函数也不用返回,引入的组件也不需要通过通过 components注册了,
    < script setup>语法糖里面的代码会被编译成组件 setup() 函数的内容
  • 组件通信: 父子组件直接传值逻辑更清晰了(defineProps,defineEmits)。
  • 父组件是无法通过ref 或者 $parent 获取到子组件的属性,需要先通过defineExpose 主动暴露,defineExpose+ref

setup接收参数(props ,context)

  • props 里面包含父组件传递给子组件的所有数据,子组件中使用 props 进行接收. 且props 是响应式的,所以不能使用 ES6 解构,它会消除 prop 的响应性。如果需要解构 prop,可以使用 toRefs 函数来完成
  • context 里面包含 attrs, slots, emit 等数据方法:
  • attrs:获取组件上的属性 slots:获取 slot 插槽的节点 emit :emit 方法(子组件向父组件传递数据)

.ref reactive toRef 和 toRefs

  • .ref 响应式监听 然后可以使用.value访问或更改响应式变量的值: 解决.value问题 reactive 与 toRefs 1.首先使用 reactive 创建响应式对象state,封装数据 2.在返回时使用 …toRefs(state) 因为toRefs(state) 将state对象展开,并包装成多个响应数据。
  • toRef 和 toRefs 都可以用来复制 reactive 里面的属性然后转成 ref,复制的属性修改后,除了视图会更新,原有 reactive 里面对应的值也会跟着更新
  • toRef: 复制 reactive 里的单个属性并转成 ref toRef(state, ‘name’);
  • toRefs: 复制 reactive 里的所有属性并转成 ref 响应式拆解

ref和reactive定义响应式数据的区别

  • reactive仅对复杂类型有效包括数组,对象,对原始类型无效(主要的原因在于在 vue 内部的响应式的实现,是依据 proxy 实现的,但是 proxy 不适用于基本类型数据)
  • ref支持原始类型和对象 基本类型响应式依赖Object.defineProperty( ),如果ref使用的是引用类型,底层ref会借助reactive的proxy 定义响应式
  • 当 ref 在模板中使用时,作为顶层 property 被访问时,它们会被自动“解包”,所以不需要使用 .value

provide与inject

  • provide与inject可用于多级组件直接传递数据 以解决 props 深度透传的问题,小项目不想使用vux的时候
  • provide(“money”, num); // 组件提供了money属性,在子组件中使用 const money = inject(‘money’)接收money
  • provide(“changeMoney”, changeMoney);//子孙组件修改父组件的数据,通过传递一个方法过去
  • provide和inject用于跨组件通信,但是它们不能直接传递动态数据。Vue实例的provide选项需要在Vue实例挂载之前就确定,因此不能直接传递一个响应式的数据。解决办法:可以通过data函数返回一个响应式对象,并在子组件中通过inject选项来接收 或者 e m i t 和 emit和 emiton)或者Vuex

生命周期

  • setup在beforeCreate之前执行。创建的是 data 和 method
  • 在Composition API中没有beforeCreate()和created()这里两个声明周期函数了,统一都使用setup()。
  • onBeforeMount,onMounted,挂载前后,
  • onBeforeUpdate,onUpdated
  • onUnmounted 卸载组件实例后调用

路由跳转,路由参数获取

const router = useRouter();
const route = useRoute();
router.push({path:'/home', query:{id:'12' }})
route.query.id

vueX

获取Dom节点

watch和watchEffect

  • watch需要明确监听哪个属性,watchEffect会根据其中的属性,自动监听其变化
  • watchEffect初始化时,一定会执行一次,且只能获取变化后的值,watch需要另外设置才会执行
父组件
<template>
    <div>
        <button @click="clickFun">按钮</button>
        <div>{{ msg }}</div>
        <page1 :num="num">
          插槽里的内容
          <template v-slot:footer>
            <p>多个插槽时候使用具名插槽</p>
          </template>
        </page1>
    </div>
</template>
<script setup>
//setup语法题写法
//defineProps 获取父组件传值
//defineEmits 触发父组件事件传值
import { inject, ref, toRefs, watchEffect, provide } from "vue";
import page1 from "./home.vue";
//const props = defineProps(["msg"])
const props = defineProps({
    msg: {
        type: String,
        required: true,
        default: "",
    },
    age: Number,
});

let num = ref(10);
const changeMoney = (n) => {
    num.value = n;
};
provide("money", num); // 组件提供了money属性,在子组件中使用 const money = inject('money')接收money
provide("changeMoney", changeMoney);//子孙组件修改父组件的数据,通过传递一个方法过去
const emit = defineEmits(["subInfo", "subItem"]);
const clickFun = () => {
    console.log(props.msg);
    num.value++;
    emit("subInfo", num.value);
};
</script>
子组件
<template>
    <div>
        <p>money=====>{{money}}</p>
        <button @click="fn">home组件修改</button>
        {{num}}
        <slot></slot>
        <slot name="footer"></slot>
    </div>
</template>
<script setup>
    import {ref, toRefs ,watchEffect,inject} from "vue"
    const props = defineProps({
        num:Number
    })
    const money = inject('money')
    const changeMoney = inject('changeMoney')
    const fn = () => {
		changeMoney(200000) // 子传父,使用changeMoney方法 修改money的值
	}
    //const emit = defineEmits(["subInfo", "subItem"])
    
    // let num = ref(10); 
    // const clickFun =()=>{
    //     console.log(props.msg)
    //     num.value++
    //     emit("subInfo", num.value)
    // }
</script>
<template>
  <div class="hello">
    <p ref="myRef">count----{{ count }}</p>
  </div>
</template>

<script>
import { ref, computed, watch, watchEffect, reactive, toRef,toRefs,onBeforeMount } from "vue";

export default {
  name: "HelloWorld",
  props: ["msg"],
  //因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性。如果需要解构 prop,可以使用 toRefs 函数来完成
  setup(props,context) {
    console.log(props);
    console.log(context);
    //使用 reactive 创建响应式对象,封装数据,在return时使用 ...toRefs(state)
    const state = reactive({
      number: 124,
      doubleCount: computed(() => state.number *2),
    });
    //computed计算属性  它接受 getter 函数并为 getter 返回的值返回一个不可变的响应式 ref 对象
    let num1 = ref(4);
    const msgStr = ref(props.msg);
    const userID = ref(2222);
    //获取dom节点
    const myRef = ref(null);

    const count = computed({
      get: () => {
        console.log("computed get");
        return state.number + 100;
      },
      set: (val) => {
        console.log("computed set");
        console.log(val);
      },
    });

    watch(
      num1,
      (newVal, oldVal) => {
        console.log(newVal, "新的");
        console.log(oldVal, "旧的");
      },
      { immediate: true, deep: true }
    );
    //监听对象中的某个具体数据,vue做了优化,使用 watch 监听 reactive 的时候可以不添加 deep 属性,也能够对其做深度监听
    watch(()=>state.number, (newVal, oldVal) => {
      console.log(newVal, oldVal)
    });
    //监听多个数据 注意多个同步更改只会触发一次侦听器。
    watch([()=>state.number,num1],(newVal,oldVal)=>{
      console.log(newVal, oldVal)//[124, 123] => [124, 4]
    })

    //watchEffect 会返回一个用于停止这个监听的函数
    const stop = watchEffect(() => {
      console.log('watchEffect',count.value)
      console.log('watchEffect',msgStr.value)
    });
    //stop()

    function edit() {
      console.log(props.msg);
      context.emit('childFun','子组件的值')
      console.dir(myRef.value);
      
    }
    return {
      fun: () => {
        num1.value = 123;
      },
      ...toRefs(state),
    };
  },
};
</script>

vue2和3响应式原理

1.ref 被ref函数包裹基本数据类型 返回一个 ref 引用实例对象,被包裹的对象它内部会通过 reactive函数转为代理对象
2.reactive reactive包裹一个对象或数组,返回一个被包裹后的proxy代理对象
3.vue2.0响应式存在的问题:通过对 object.defindProperty() 对属性的读取 修改进行拦截,如果新增属性,删除属性也不会进行更新。需要nextTick处理下
4.vue3通过 Proxy代理,拦截对象中任意属性的变化,包括对象的新增属性,删除属性没有这个问题

自定义hooks函数

用hooks来实现类似vue2的mixins的功能。其实是函数的写法,就是将文件的一些单独功能的js代码进行抽离出来,复用功能代码的来源, 更清晰易懂
1.首先应该先在src下建立一个hooks文件夹:其目的是为了存放hook文件。
2.建立相关的hook文件:一般使用use开头。
3.使用
import useCounter from “./hooks/useCounter.js”;
const { user, hooksFun } = useCounter();

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值