当前位置: 首页 > news >正文

VUE从入门到精通二:ref、reactive、computed计算属性、watch监听、组件之间的通信

目录

一、ref、reactive创建响应式对象

1、ref()

2、reactive()

3、ref和reactive的区别

二、computed计算属性

1、什么是计算属性computed

2、计算属性computed和函数方法的区别

3、计算属性computed的优势

三、watch监听函数

1、什么是watch?

2、基本语法

3、深度监听

4、使用字符串路径监听嵌套属性

5、动态添加watcher

6、立即执行watcher

7、一次性监听

8、停止watcher

9、watch vs watchEffect监听方式对比

10、watch与computed的区别

11、watch vue3与vue2的对比

12、性能优化建议

13、完整示例

四、组件之间的通信

1、Props(父传子)

 2、Emit(子传父)

3、Provide / Inject(祖先传后代)

4、Vuex全局事件总线(状态管理)


一、ref、reactive创建响应式对象

1、ref()

在Vue 3中,ref是一个函数,用于创建一个响应式引用。它可以定义基本数据类型(如字符串、数字、布尔值等)。虽然也可用于创建对象和数组,但更推荐使用reactive。使用ref时,需要通过.value属性来访问和修改数据。

const copy_address_type = ref('')  // 地址同步文案
const exemption_fax = ref(0.00) //消费税
const exemption_no_show = ref(false)

2、reactive()

reactive它更适用于创建对象和数组。reactive会将整个对象或数组转换为响应式的,这意味着对象或数组中的每个属性都会被代理。

const form_data = reactive({id: '', type:'', first_name: '',last_name: '',email: '',phone: '',institution: '',postcode: '',address: '',city: '',state_input: '',state: '',country: '', set_copy_address: ''
})
const country_data = ref([])

3、ref和reactive的区别

a.数据类型:ref适用于基本数据类型及复杂对象,而reactive主要用于复杂对象及嵌套数据结构。

b.访问方式:ref通过.value属性访问,而reactive直接通过属性访问。

c.响应性追踪:ref追踪单个独立的引用,reactive追踪整个对象及其内部属性。

d.可变性:ref的引用值可以重新赋值,而reactive对象本身是不可重新赋值的,只能修改其内部属性。

二、computed计算属性

1、什么是计算属性computed

computed‌是用于基于其他响应式数据动态计算新数据的工具,具有缓存机制,仅在依赖数据变化时重新计算,可显著提升性能,如果依赖的数据不变化,computed永远不会改变。

核心特性

‌依赖缓存‌:仅在依赖数据(如响应式引用)变化时重新计算,避免重复执行。 ‌

‌声明式定义‌:通过computed函数定义,支持复杂逻辑复用。 ‌

‌性能优化‌:减少模板渲染时的计算开销,提升渲染效率。

<template><div>{{ double }}</div><input v-model="count" />
</template><script setup>import { ref, computed } from 'vue';const count = ref(1);const double = computed(() => count.value * 2);
</script>

上面的例子,当文本框的count发生改变时,double数据也会发生变化。

2、计算属性computed和函数方法的区别

function doubleFunc(count) {let double = count * 2return double}

若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books 不改变,无论多少次访问 double 都会立即返回先前的计算结果,而不用重复执行doubleFunc函数。

这也很好的解释了下面的计算属性永远不会更新,因为 Date.now() 并不是一个响应式依赖,它不会变化。

const now = computed(() => Date.now())

3、计算属性computed的优势

A.简洁高效:通过计算属性computed可以简洁高效地实现基于其他属性计算的属性,避免了重复计算和代码冗余。

B.响应式更新:计算属性computed会自动响应依赖的变化而更新,保持界面和数据的同步。

C.缓存机制:计算属性computed会缓存计算结果,只有在相关依赖发生改变时才会重新计算,提高了性能和效率。

三、watch监听函数

1、什么是watch?

watch是Vue中用于监听数据的变化并执行相应的操作。

当被监听的数据发生变化时,会触发一个回调函数,我们可以在这个回调函数中执行一些逻辑操作。

watch适用于需要在数据变化时执行异步或较复杂的场景。

2、基本语法

export default {setup() {const count = ref(0);watch(count, (newVal, oldVal) => {console.log(`count changed from ${oldVal} to ${newVal}`);});return { count,};}
};

3、深度监听

对于对象或数组的监视,默认情况下,Vue不会递归地监视对象内部属性的变化。如果你需要深度监视,vue2中可以设置deep选项为true。Vue3中你可以使用watchEffect或者watch函数,并通过提供一个回调函数来访问和监视这些深层属性。

Vue2深度监听

export default {data() {return {user: {name: '张三',age: 25}}},watch: {user: {handler(newValue, oldValue) {console.log('user对象变化了', newValue, oldValue)},deep: true // 开启深度监听}}
}

VUE3深度监听

import { ref, watchEffect } from 'vue';const obj = ref({nested: {prop: 'value'}
});watchEffect(() => {console.log(obj.value.nested.prop); // 访问深层属性
});// 更新深层属性时,控制台将显示新值
obj.value.nested.prop = 'new value';

深度监听原理:

    4、使用字符串路径监听嵌套属性

    const city = computed(() => state.user.address.city);
    watch(city, (newValue, oldValue) => {console.log(`City changed from ${oldValue} to ${newValue}`);
    });

    5、动态添加watcher

    如果你需要在组件的生命周期内动态添加watcher,可以使用Vue实例的$watch方法

    export default {mounted() {this.$watch('message', (newVal, oldVal) => {console.log(`message changed from ${oldVal} to ${newVal}`);});}

    6、立即执行watcher

    默认情况下,watch只会在数据变化时触发回调函数,而不会在初始化时执行。

    如果需要在初始化时就执行一次回调函数,可以设置immediate: true。

    watch(() => obj.value.nested.prop, // 监视深层属性(newValue, oldValue) => {console.log(`Prop changed from ${oldValue} to ${newValue}`);},{ immediate: true } // 立即执行一次回调
    );

    7、一次性监听

    可以使用once: true选项来设置只监听一次变化
    // 使用 once 选项让 watch 只监听一次

    watch(count, (newValue, oldValue) => {console.log(`Count changed from ${oldValue} to ${newValue}`);
    }, { once: true });

    8、停止watcher

    当你使用$watch方法添加watcher时,可以通过返回的取消函数来停止watcher:

    const count = ref(0);
    let stopWatch;
    stopWatch = watch(count, (newVal, oldVal) => {console.log(`Count changed from ${oldVal} to ${newVal}`);
    });
    onUnmounted(() => {stopWatch(); // 确保在组件卸载时停止watcher
    });

    9、watch vs watchEffect监听方式对比

    watch需要明确指定要监听的数据源,而watchEffect会自动收集其内部所使用的所有响应式依赖。
    watch可以访问被监听状态的前一个值和当前值,而watchEffect只能访问当前值。
    watchEffect会在组件初始化时立即执行一次,相当于设置了immediate: true的watch。

    const count = ref(0)
    const message = ref('Hello')// watchEffect会自动监听回调函数中使用的所有响应式数据
    watchEffect(() => {console.log(`count: ${count.value}, message: ${message.value}`)
    })
    // 等价于以下watch写法
    watch([count, message], ([newCount, newMessage]) => {console.log(`count: ${newCount}, message: ${newMessage}`)
    }, { immediate: true })

    10、watch与computed的区别

    特性

    watch

    computed

    用途

    监听数据变化并执行副作用

    计算并返回新值

    缓存

    无缓存机制

    有缓存,只在依赖变化时重新计算

    返回值

    无返回值

    有返回值

    适用场景

    数据变化时执行异步操作或复杂逻辑

    依赖其他数据计算出新值

    执行时机

    数据变化后执行

    依赖变化时立即计算新值

    11、watch vue3与vue2的对比

    // Vue 2 选项式 API
    watch: {user: {handler(newVal) { /*...*/ },deep: true}
    }// Vue 3 组合式 API(更灵活)
    const user = reactive({/*...*/})
    watch(user, (newVal) => {/*...*/}, { deep: true })

    12、性能优化建议

    避免过度深度监听:只对必要对象开启
    使用精确监听路径

    watch(() => user.address.city, (newCity) => {...})及时清理监听
    const stopWatch = watch(...)
    onUnmounted(stopWatch) // 组件卸载时停止监听

    13、完整示例

    const user = reactive({id: 1,info: {name: '张三',address: {city: '北京',street: '朝阳区'}}
    })// 深度监听整个用户对象
    watch(user,(newUser) => {console.log('用户信息已修改,自动保存...')autoSave(newUser)},{ deep: true, immediate: true }
    )// 精确监听城市变化
    watch(() => user.info.address.city,(newCity) => {updateMap(newCity)}
    )

    四、组件之间的通信

    1、Props(父传子)

    父组件通过props向下传递数据给子组件。这是最常见的父子组件通信方式。

    父组件

    <template><ChildComponent :message="parentMessage" />
    </template><script setup>
    import ChildComponent from './ChildComponent.vue';
    import { ref } from 'vue';const parentMessage = ref('Hello from parent');
    </script>

    子组件

    <template><div>{{ message }}</div>
    </template><script setup>
    defineProps({message: String
    });
    </script>

     2、Emit(子传父)

    子组件通过emit向父组件发送事件和数据。

    子组件

    <template><button @click="sendMessage">Send Message</button>
    </template><script setup>
    import { defineEmits } from 'vue';const emit = defineEmits(['updateMessage']);function sendMessage() {emit('updateMessage', 'Hello from child');
    }
    </script>

    父组件

    <template><ChildComponent @updateMessage="handleMessage" />
    </template><script setup>
    import ChildComponent from './ChildComponent.vue';
    import { ref } from 'vue';const childMessage = ref('');
    function handleMessage(msg) {childMessage.value = msg;
    }
    </script>

    3、Provide / Inject(祖先传后代)

    provide和inject可以用于跨多级组件传递数据,非常适合在深层嵌套的组件结构中通信。

    祖先组件

    <template><DescendantComponent />
    </template><script setup>
    import { provide, ref } from 'vue';
    import DescendantComponent from './DescendantComponent.vue';const message = ref('Hello from ancestor');
    provide('message', message); // 提供数据给后代组件使用
    </script>

    后代组件

    <template><div>{{ message }}</div>
    </template><script setup>
    import { inject } from 'vue';
    const message = inject('message'); // 注入数据从祖先组件接收数据
    </script>

    4、Vuex全局事件总线(状态管理)

    对于更复杂的应用,可以使用Vuex进行状态管理,实现任意跨组件的通信。Vuex提供了一个集中存储管理应用所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

    使用:

    第一步:#src/store/index.js 创建vuex模块文件,开始使用vuex

    在一个模块化的打包系统中,您必须显式地通过 `Vue.use()` 来安装 Vuex:

    import Vue from 'vue'
    import Vuex from 'vuex'
    Vue.use(Vuex)

    第二步:#实例化Vuex.store ,并进行相关配置

    export default new Vuex.Store({state: {//存储状态},mutations: {//变更store中的状态},actions: {//类似于mutation,//action提交的是mutation,而不是直接变更状态//action可以包含异步操作},getters:{//state的派生状态  },modules: {//将store分割成模块}
    })

    第三步:#在main.js中,vue实例对象中注册store

    import store from './store'
    new Vue({store,render: h => h(App)
    }).$mount('#app')

    每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)

    http://www.dtcms.com/a/342545.html

    相关文章:

  1. 网络与信息安全有哪些岗位:(5)安全开发工程师
  2. Android14内核调试 - boot vendor_boot
  3. Git常用操作大全(附git操作命令)
  4. Matplotlib数据可视化实战:Matplotlib数据可视化入门与实践
  5. golang实现的Rsa加密解密算法(go和java交互时双向加解密方案)
  6. OpenCV 形态学操作详解:腐蚀、膨胀与开闭运算
  7. Chrome/360 浏览器 WebUI 资源底层机制解析:共享资源与专属资源的奥秘
  8. 一、部署LNMP
  9. mac的m3芯片安装JDK8、JDK17
  10. 【CDA干货】金融App产品AB测试与指标体系搭建
  11. 数据结构之排序大全(3)
  12. 31、工业网络异常行为检测与OT协议深度分析 (核电站DCS模拟) - /安全与维护组件/network-anomaly-detection-nuclear
  13. “码” 上安全:轻量级加密的硬件实现与侧信道攻击防御
  14. Java实现一个简单的LRU缓存对象
  15. 【SpringBoot】16 核心功能 - Web开发原理 - 请求参数 - 源码分析
  16. WindowsAPI|每天了解几个winAPI接口之网络配置相关文档Iphlpapi.h详细分析七
  17. 如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
  18. CTFshow系列——命令执行web41-44
  19. YOLOv8 原理与跨领域应用全景分析
  20. CVPR | 2025 | MAP:通过掩码自回归预训练释放混合 Mamba - Transformer 视觉骨干网络的潜力
  21. 【C++】仿函数和回调函数
  22. Python数值取整完全指南:从基础到金融工程实践
  23. uniapp实现分页,效果如图
  24. 自然语言处理——04 注意力机制
  25. npm全局安装后,cmd命令行可以访问,vscode访问报错
  26. HTTP 403 错误:后端权限校验机制深度解析
  27. 长尾关键词优化SEO核心策略
  28. JeeSite 快速开发平台:全能企业级快速开发解决方案
  29. 自己动手,在Mac开发机上利用ollama部署一款轻量级的大模型Phi-3:mini
  30. ElasticSearch——常用命令