
01-vue3学习整理 
主要记录一下Vue3的知识
推荐博客:http://web.wiyp.top/#/Vue/VueBook33
官网:https://cn.vuejs.org/guide/quick-start.html
Vue3+element plus 脚手架:https://gitee.com/lzh1995/vue3-demo
生命周期 
共8个:
- 实例生成之前会自动执行的函数- - -beforeCreate()
 - 实例生成之后会自动执行的函数- - -created()
 - 组件内容被渲染到页面之前自动执行的函数- - -beforeMount()
 - 组件内容被渲染到页面之后自动执行的函数- - -mounted()
 - 数据发生变化时会立即自动执行的函数- - -beforeUpdate()
 - 数据发生变化后,页面重新渲染后,会自动执行的函数- - -updated()
 - 当 Vue 应用失效时,会自动执行的函数- - -beforeUnmount()
 - 当 Vue 应用失效时,且 dom 完全销毁之后,自动执行的函数- - -unmounted()
 
vue
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured使用
vue
<script setup>
import { onBeforeMount, onMounted } from 'vue'
onBeforeMount(() => {
  // 在组件挂载前执行的代码
})
onMounted(() => {
  // 在组件挂载后执行的代码
})
</script>完整示例
html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>生命周期函数</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
    /*
        生命周期函数:在某一时刻,会自动执行的函数
        8个:
        1. 实例生成之前会自动执行的函数- - -beforeCreate()
        2. 实例生成之后会自动执行的函数- - -created()
        3. 组件内容被渲染到页面之前自动执行的函数- - -beforeMount()
        4. 组件内容被渲染到页面之后自动执行的函数- - -mounted()
        5. 数据发生变化时会立即自动执行的函数- - -beforeUpdate()
        6. 数据发生变化后,页面重新渲染后,会自动执行的函数- - -updated()
        7. 当 Vue 应用失效时,会自动执行的函数- - -beforeUnmount()
        8. 当 Vue 应用失效时,且 dom 完全销毁之后,自动执行的函数- - -unmounted()
        */
    // 创建vue实例
    const app = Vue.createApp({
        // 1. 实例生成之前会自动执行的函数
        beforeCreate() {
            console.log('beforeCreate');
        },
        // 2. 实例生成之后会自动执行的函数
        created() {
            console.log('created');
        },
        // data里面定义了组件要展示的数据,数据层- - -model
        data() {
            return {
                message: 'hello world'
            }
        },
        // 3. 组件内容被渲染到页面之前自动执行的函数
        beforeMount() {
            console.log(document.getElementById('root').innerHTML, 'beforeMount');
        },
        // 4. 组件内容被渲染到页面之后自动执行的函数
        mounted() {
            console.log(document.getElementById('root').innerHTML, 'mounted');
        },
        // 5. 数据发生变化时会立即自动执行的函数
        beforeUpdate() {
            console.log(document.getElementById('root').innerHTML, 'beforeUpdate');
        },
        // 6. 数据发生变化后,页面重新渲染后,会自动执行的函数
        updated() {
            console.log(document.getElementById('root').innerHTML, 'updated');
        },
        // 7. 当 Vue 应用失效时,会自动执行的函数
        beforeUnmount() {
            console.log(document.getElementById('root').innerHTML, 'beforeUnmount');
        },
        // 8. 当 Vue 应用失效时,且 dom 完全销毁之后,自动执行的函数
        unmounted() {
            console.log(document.getElementById('root').innerHTML, 'unmounted');
        },
        // 视图模板---view
        template: '<div>{{message}}</div>'
    });
    // 将实例挂载到具体的dom节点,vm 是 数据-视图 连接层
    const vm = app.mount('#root');
    // 修改message值,注意调用data里面的数据,要在data前加上 $ 符号
    vm.$data.message = '你好呀!';
    // app.unmount('#root');
</script>
</html>结果:
html
beforeCreate
created
beforeMount
<div>hello world</div> mounted
<div>hello world</div> beforeUpdate
<div>你好呀!</div> updated变量 
reactive 和 ref 是 Vue 3 中的两种响应式数据绑定方式,ref 适用于简单的响应式数据,而 reactive 则适用于复杂对象或数组的响应式数据。
ref:使用 .value 属性来访问和修改值。
reactive:可以直接访问和修改对象或数组的属性或元素,而无需使用 .value。
vue
import { ref, reactive } from 'vue';
// ref示例
const count = ref(0);
console.log(count.value); // 访问值
count.value += 1; // 修改值
// reactive示例
const state = reactive({
  name: 'Alice',
  age: 25,
});
console.log(state.name); // 访问属性
state.age += 1; // 修改属性全局变量 
在Vue 3中,由于不再直接暴露Vue构造函数,传统的通过Vue.prototype挂载全局方法的方式不再适用。取而代之的是,你可以使用应用的app.config.globalProperties来挂载全局方法
main.js 设置全局变量。
js
import { createApp } from 'vue'
const app = createApp(App);
 
/**定义变量$website,并赋值为devcursor**/
app.config.globalProperties.$website = '卡卡罗特';
app.config.globalProperties.$myGlobalMethod = function() {
    alert('This is a global method');
};在模版使用
vue
<template>
  <div>{{ $website }}</div>
</template>在js使用
shell
<script setup>
import { getCurrentInstance } from 'vue'
//获取方法1
const app = getCurrentInstance()
const website = app.appContext.config.globalProperties.$website
console.log(website)
//获取方法2
const app = getCurrentInstance()
const {$website,$myGlobalMethod} = app.appContext.config.globalProperties
console.log($website)
//方法执行
$myGlobalMethod()
 
//获取方法3
const { proxy } = getCurrentInstance()
console.log(proxy.$website)
</script>shell
<script>
export default {
  name: 'HelloWorld',
  created() {
    alert(this.$website);
  },
}
</script>组件传值 
setup 语法糖 
父传子-defineProps 
主要是 用vue的 defineProps 来接收数据
父页面
vue
<Home :data2="[1,2]"/>子组件 Home.vue
vue
<template>
    <div>
        我是子组件
    </div>
</template>
<script setup>
    import { defineProps } from 'vue'
    const props = defineProps({
        data2: {
            default: [],
            type: Array,
        },
    });
    console.log(props.data2)
</script>子传父-defineEmits 
javascript
// 子组件:创建自定义事件,传递数据
const emit = defineEmits(['自定义事件']);
emit('自定义事件', 数据1, 数据2);
 
// 父组件:绑定自定义事件,接收数据
<组件标签 @自定义事件="函数名"></组件标签>
 
const 函数名 = (参数1, 参数2) => {
  console.log(参数1, 参数2);
}父组件
vue
<Home  @clickChild="clickEven"/>
<script setup>
    const clickEven=(val1,val2)=>{
      console.log(val1,val2);
    }
</script>子组件
vue
<template>
    <div>
        <el-button type="primary" @click="alert2">按钮</el-button>
    </div>
</template>
<script setup>
    import { defineEmits  } from 'vue'
    // 使用defineEmits创建名称,接受一个数组
    const emit = defineEmits(['clickChild'])
    function alert2() {
        //传递给父组件
        let param={
            content:'b'
        }
        emit('clickChild',param,"cccc")
    }
</script>父传孙 
注意
正常情况下,父子组件之间的数据传递需要用到 props 属性,这里就会有问题,如果父组件的数据需要送到 N 层子组件, 那么就要传递 N 次 props 属性,非常繁琐,而 provide / inject 就是用来解决 props 多层嵌套的问题,有了它, 只需声明一次数据就够了,使用方式也很简单。
在组合式 API 中使用 provide/inject,两个只能在 setup 期间调用,使用之前,必须从 vue 显示导入 provide/inject 方法。

provide 函数接收两个参数:
provide( name,value )
name:定义提供 property 的 name 。
value :property 的值。
使用时:
js
import { provide } from "vue"
export default {
  setup(){
    provide('info',"值")
  }
}inject 函数有两个参数:
inject(name,default)
name:接收 provide 提供的属性名。
default:设置默认值,可以不写,是可选参数。
js
import { inject } from "vue"
export default {
  setup(){
    inject('info',"设置默认值")
  }
}完整实例1:provide/inject实例
vue
//父组件代码
<script>
import { provide } from "vue"
export default {
  setup(){
    provide('info',"值")
  }
}
</script>
//子组件 代码
<template>
 {{info}}
</template>
<script>
import { inject } from "vue"
export default {
  setup(){
    const info = inject('info')
    return{
      info
    }
  }
}
</script>父直接获取子的属性 
在 Vue 3 中,你可以使用 ref 属性在父组件中引用子组件实例,然后直接访问其内部的可公开的属性或方法。
注意:
父组件:通过ref获取子组件实例
子组件:通过defineExpose暴露方法
子组件 (ChildComponent.vue):
vue
<template>
    <div>
        <!-- 子组件模板 -->
    </div>
</template>
<script setup>
  import { ref, defineExpose } from "vue";
  const userName = ref("张三");
  function doSomething() {
    return "写代码"
  }
  // 暴露方法
  defineExpose({
    doSomething,
    userName,
  });
</script>父组件 (ParentComponent.vue):
vue
<template>
  <div style="text-align:center">
    <button @click="callChildMethod">点击获取子组件数据</button>
    <div>
      获取到子组件的数据如下:
      <div> {{childData}} </div>
    </div>
    <ChildComponent ref="ChildComponentRef"/>
  </div>
</template>
<script setup>
  import { ref } from "vue";
  import ChildComponent from "@/components/ChildComponent.vue";
  const ChildComponentRef = ref(null); // 获取子组件实例(需要跟ref处同名)
  let childData = ref();
  const callChildMethod = () =>{
    if (ChildComponentRef.value) {
      childData.value = ChildComponentRef.value.userName +'在'+ ChildComponentRef.value.doSomething()
    }
  }
</script>消息总线通信 
比如兄弟组件的通信,我感觉很方便。
shell
yarn add mittutils/mitter.js
js
import mitt from 'mitt';
const mitter = mitt();
export default mitter;X.vue
vue
<template>
    <button @click="getData()">获取数据</button>
</template>
<script setup>
    import mitter from '@/utils/mitter';
    function getData() {
        // 发送事件
        mitter.emit('eventName', "123");
    }
</script>Y.vue
vue
<template>
    {{list}}
</template>
<script setup>
    import { ref  } from "vue";
    import mitter from '@/utils/mitter';
    let list = ref()
    // 监听事件
    mitter.on('eventName', (data) => {
        list.value = data
    });
</script>声明变量 
文档: https://cn.vuejs.org/guide/essentials/reactivity-fundamentals.html
shell
<script setup>
import { reactive } from 'vue'
const state = reactive({ count: 0 })
</script>
<template>
<button @click="state.count++">
  {{ state.count }}
</button>
</template>计算属性 
shell
import { computed, reactive } from 'vue'
const state = reactive({
  count: 0
})
const doubleCount = computed(() => {
  return state.count * 2
})
console.log(doubleCount.value) // 输出:0
state.count = 1
console.log(doubleCount.value) // 输出:2监听属性 
第一种写法
vue
<script setup>
import { inject, watch } from 'vue';
const activeCategory = inject('active')
watch(activeCategory, (newVal) => {
   //业务逻辑
})
</script>第二种写法
vue
<template>
  <div>{{ value }}</div>
</template>
<script>
import { watch } from 'vue';
export default {
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  setup(props) {
    watch(() => props.value, newValue => {
      console.log(`Value changed to: ${newValue}`);
      // 在这里执行你需要的操作
    }, {
      immediate: true // 可选:如果希望在初始渲染时也触发一次观察器
    });
    // 返回其他需要暴露给模板的数据或方法
  }
};
</script>如何使用$refs 
如何在 Vue3 的 setup 中使用 $refs
第一种 
通过 ref() 函数,依然可以实现类似 this.$refs 的功能。
首先在 setup 中定义一个 Ref 变量,然后将这个 registerFormRef 变量挂载到 DOM 上
vue
<script setup>
import { ref } from 'vue'
const registerFormRef = ref()
registerFormRef.validate((valid) => {
    
})
</script>
<template>
   <el-form  ref="registerFormRef"></el-form>
</template>第二种 
通过 getCurrentInstance() 可以获得 vue 实例对象。
vue
<template>
    <el-form  ref="registerFormRef"></el-form>
</template>
<script setup>
    import {getCurrentInstance} from 'vue'
    const app = getCurrentInstance()
    function registerUser() {
      app.proxy.$refs.registerFormRef.validate((valid) => {
        if (valid) {
          // 业务逻辑
        }
      });
    }
</script>nextTick 
配合异步
vue
import {reactive, ref,nextTick} from 'vue'
setup() {
    const message = ref('Hello!')
    const changeMessage = async newMessage => {
      message.value = newMessage
      await nextTick()
      console.log('Now DOM is updated')
    }
  }普通使用
js
import {reactive, ref,nextTick} from 'vue'
let otherParam = reactive({
  showA:false
})
nextTick(()=>{
  console.log('Now DOM is updated')
})
