watch、computed和method的区别以及与props,data的加载顺序

本文详细介绍了Vue.js中计算属性(computed)与监听机制(watch)的使用方法及区别。计算属性适用于一个数据受多个数据影响的情况,而监听机制则适用于一个数据的变化需要触发多个数据更新或执行异步操作的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • computed

  • 当页面中有某些数据 依赖 其他数据 进行变动的时候,可以使用计算属性。

  • 需要注意的是,就算在 data中没有直接声明 出要计算的变量,也可以直接在computed中写入。

  • 计算属性默认只有getter,可以在需要的时候自己设定setter:

  • 使用场景:computed擅于处理:一个数据受多个数据影响

  • 即在这多个依赖数据中,任何一个改变都会导致 受影响的数据的改变

computed: {
    fullName: {
      // getter
      get: function () {
        return this.firstName + ' ' + this.lastName
      },
      // setter
      set: function (newValue) {
        var names = newValue.split(' ')
        this.firstName = names[0]
        this.lastName = names[names.length - 1]
      }
    }
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
  • watch
  • data中没有相应的属性的话,是不能watch
  • watch:类似于监听机制+事件机制:一个数据影响多个数据。
  • 适合监控场景,某【一个】变量改变时需要做什么操作;
  • 在数据变化的同时进行异步操作或者是比较大的开销,
  • watch为一个对象,键是需要观察的表达式,
    值是对应回调函数。值也可以是方法名,或者包含选项的对象。
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  },

vue组件props,methods,data,computed,watch的加载顺序

在这里插入图片描述

props - > methods - > data - > computed - > watch

父组件向子组件通过props传值,props是一个只读属性,
如果要改变props的值,需要在data中进行定义,
所以props在前,data在后
computed计算属性要使用data里面的数据,
所以data在前,computed在后

vue的props,data,computed的加载顺序的影响
1.因为加载顺序: props->methods->data->computed->watch

2.computed与watch只能作为变化监听,千万不能做初始化!!!

3.所有的init方法必须直接调用数据库或者直接this.$store.getters读取内存而不是通过computed去获取

<template> <div class="custom-tree-container"> <!-- 搜索框 --> <el-input v-if="showSearch" v-model="filterText" placeholder="输入关键字过滤" clearable class="tree-search" /> <!-- 树形组件 --> <el-tree ref="treeRef" :data="processedData" :props="mergedProps" :node-key="nodeKey" :lazy="lazy" :load="loadNode" :show-checkbox="showCheckbox" :highlight-current="highlightCurrent" :default-expand-all="defaultExpandAll" :expand-on-click-node="expandOnClickNode" :filter-node-method="filterNode" @node-click="handleNodeClick" @check-change="handleCheckChange" > <!-- 自定义节点内容 --> <template #default="{ node, data }"> <span class="custom-node"> <slot name="prefix-icon" :node="node"> <el-icon v-if="showDefaultIcon"><FolderOpened /></el-icon> </slot> <span class="node-label">{{ node.label }}</span> <slot name="suffix-content" :node="node" :data="data" /> </span> </template> </el-tree> </div> </template> <script setup> import { ref, computed, watch } from 'vue' import { FolderOpened } from '@element-plus/icons-vue' const props = defineProps({ // 原始数据 data: { type: Array, required: true }, // 树形配置项 treeProps: { type: Object, default: () => ({ label: 'label', children: 'children', disabled: 'disabled', isLeaf: 'isLeaf' }) }, nodeKey: { type: String, default: 'id' }, showSearch: Boolean, showCheckbox: Boolean, showDefaultIcon: { type: Boolean, default: true }, highlightCurrent: { type: Boolean, default: true }, defaultExpandAll: Boolean, expandOnClickNode: Boolean, lazy: Boolean, loadFn: Function // 异步加载函数 }) const emit = defineEmits(['node-click', 'check-change', 'data-filtered']) const filterText = ref('') const treeRef = ref(null) // 合并默认配置自定义配置 const mergedProps = computed(() => ({ ...props.treeProps })) // 数据处理(可根据需要添加转换逻辑) const processedData = computed(() => { // 这里可以添加数据转换逻辑 return props.data }) // 过滤方法 const filterNode = (value, data) => { return data[mergedProps.value.label].includes(value) } // 节点点击事件 const handleNodeClick = (data, node) => { emit('node-click', { data, node }) } // 复选框变化事件 const handleCheckChange = (data, checked, indeterminate) => { emit('check-change', { data, checked, indeterminate }) } // 异步加载节点 const loadNode = async (node, resolve) => { // console.log(node); if (typeof props.loadFn === 'function') { console.log(props.loadFn); const children = await props.loadFn(node) console.log(children); // console.log(resolve); // console.log(resolve(children || [])); resolve(children || []) } } // 监听搜索过滤 watch(filterText, (val) => { treeRef.value?.filter(val) emit('data-filtered', val) }) // 暴露方法 defineExpose({ getCheckedNodes: () => treeRef.value?.getCheckedNodes(), setCheckedKeys: (keys) => treeRef.value?.setCheckedKeys(keys), filter: (value) => treeRef.value?.filter(value) }) </script> <style scoped> .custom-tree-container { padding: 10px; background: #fff; border-radius: 4px; } .tree-search { margin-bottom: 10px; } .custom-node { display: flex; align-items: center; padding: 5px 0; } .node-label { margin-left: 6px; } :deep(.el-tree-node__content) { height: 36px; } </style> 解析代码
03-08
在 Vue 中,`computed`(计算属性)是一种非常强大的功能,用于**声明式地描述依赖于其他数据的值**。它会基于其响应式依赖进行缓存,只有当依赖发生变化时才会重新计算。 --- ## ✅ 基本用法 ### 示例 1:基础计算属性 —— 拼接字符串 ```vue <template> <div>Full Name: {{ fullName }}</div> </template> <script> export default { data() { return { firstName: 'John', lastName: 'Doe' }; }, computed: { fullName() { return this.firstName + ' ' + this.lastName; } } }; </script> ``` > 当 `firstName` 或 `lastName` 发生变化时,`fullName` 会自动更新。 --- ### 示例 2:带逻辑处理的计算属性 —— 过滤列表 ```vue <template> <ul> <li v-for="item in filteredItems" :key="item.id"> {{ item.name }} </li> </ul> </template> <script> export default { data() { return { items: [ { id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }, { id: 3, name: 'Cherry' } ], filterText: 'a' }; }, computed: { filteredItems() { return this.items.filter(item => item.name.toLowerCase().includes(this.filterText.toLowerCase()) ); } } }; </script> ``` > 计算属性返回一个过滤后的数组,模板中可以像普通属性一样使用它。 --- ## ✅ 计算属性 vs 方法(methods) | 特性 | computed | methods | |------|----------|---------| | 是否缓存 | ✅ 是(依赖未变不会重复执行) | ❌ 否(每次调用都会执行) | | 使用方式 | 属性形式 `{{ computedProp }}` | 函数调用 `{{ method() }}` | | 推荐场景 | 基于已有数据派生出新数据 | 需要传参或不依赖响应式数据 | --- ## ✅ 带 setter 的计算属性(高级用法) 你可以为计算属性提供 `get` `set`,实现双向绑定。 ### 示例: ```vue <template> <div> First Name: <input v-model="firstName"><br> Last Name: <input v-model="lastName"><br> Full Name: <input v-model="fullName"> </div> </template> <script> export default { data() { return { firstName: 'John', lastName: 'Doe' }; }, computed: { fullName: { get() { return this.firstName + ' ' + this.lastName; }, set(newValue) { const names = newValue.split(' '); this.firstName = names[0]; this.lastName = names[1]; } } } }; </script> ``` > 当你在输入框修改 `fullName` 时,会自动拆分并更新 `firstName` `lastName`。 --- ## ✅ 在组件中使用计算属性 你可以在组件内部定义自己的计算属性,它们只能访问当组件的数据 props。 ### 示例:组件内使用 computed ```vue <!-- ChildComponent.vue --> <template> <div> <p>Prop Value: {{ propValue }}</p> <p>Formatted Prop: {{ formattedProp }}</p> </div> </template> <script> export default { props: ['value'], computed: { formattedProp() { return this.value.toUpperCase(); } } }; </script> ``` --- ## ✅ 总结对比 | 功能 | computed | methods | watch | |------|----------|---------|-------| | 缓存机制 | ✅ 有缓存 | ❌ 无缓存 | ❌ 无缓存 | | 支持异步 | ❌ 不推荐 | ✅ 可以 | ✅ 可以 | | 适合场景 | 数据派生、组合多个响应式数据 | 事件处理、复杂逻辑、非响应式操作 | 监听数据变化并执行副作用 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值