Vue.js二次Ajax请求更新数据的最佳实践咨询
嘿,针对你用Vue 2.5.16实现数据更新时遇到的两个问题,我给你梳理下实用的优化思路,贴合Vue的响应式特性来搞:
一、无需手动操作的高效properties对象更新方式
首先得说,v-model确实不适合你这个场景——它主要是给表单元素做双向绑定用的,咱们这里是后端数据拉取更新,得用Vue响应式系统的正确姿势来优化:
并行请求提升加载速度
你现在是先调用properties.view()拿缓存数据,再调用available()拿库存数据,其实这俩请求可以同时发起,用Promise.all并行处理,不用等第一个完成再跑第二个,能大幅缩短页面加载时间:// 页面加载时的初始化逻辑 async initData() { const [viewRes, availableRes] = await Promise.all([ axios.get('/properties/view'), // 替换成你的view接口实际地址 axios.get(searchJs.getAttribute('webroot') + 'properties/available', { headers: {'Content-Type': 'application/json'} }) ]); this.properties = viewRes.data; this.updateAvailableData(availableRes.data); // 单独抽离更新逻辑更清晰 }高效匹配数据,避免循环遍历浪费性能
你现在用filter循环找匹配的property,数据多的时候效率很低。可以把已有的properties转成Map,用id作为key,直接快速查找:updateAvailableData(availableData) { const propMap = new Map(this.properties.map(p => [p.id, p])); availableData.forEach(p => { const targetProp = propMap.get(p.id); if (targetProp) { // 这里更新属性,后面讲深层更新的简洁写法 this.updateRateData(targetProp, p.rate); } }); }利用Vue响应式特性,减少手动$set的使用
如果你的properties数组里的对象本身是响应式的(从后端拿到后直接赋值给data里的properties,Vue已经做了响应式处理),那么只要直接修改对象的属性,Vue会自动更新视图,不需要每次都用$set——除非你是新增原本不存在的深层属性。
二、深层属性更新的简洁实现方式
你现在逐层构建对象确实麻烦,给你几个更简洁的方案:
方案1:直接赋值(适用于属性已存在的情况)
如果targetProp.rate.low.total已经存在(从properties.view()的缓存数据里就有这个结构),直接赋值就行:
updateRateData(targetProp, newRate) { targetProp.rate.low.total.nightly_avg = newRate.low.total.nightly_avg; targetProp.rate.low.total.original_nightly_avg = newRate.low.total.original_nightly_avg; }
Vue会检测到这些属性的变化,自动更新视图。
方案2:展开运算符合并对象(保留原有属性,更新指定字段)
如果需要保留rate对象里的其他属性,只更新total里的两个字段,用ES6展开运算符很方便:
updateRateData(targetProp, newRate) { targetProp.rate = { ...targetProp.rate, low: { ...targetProp.rate.low, total: { ...targetProp.rate.low.total, nightly_avg: newRate.low.total.nightly_avg, original_nightly_avg: newRate.low.total.original_nightly_avg } } }; }
这种方式不会覆盖rate里的其他未修改属性,同时Vue会因为rate对象的引用变化触发视图更新。
方案3:用$set处理新增的深层属性(如果结构原本不存在)
如果缓存数据里没有rate.low.total这个结构,是第一次新增,那得用$set来保证响应式:
updateRateData(targetProp, newRate) { // 先确保rate.low存在,不存在就创建 if (!targetProp.rate) this.$set(targetProp, 'rate', {}); if (!targetProp.rate.low) this.$set(targetProp.rate, 'low', {}); // 然后更新total里的字段 this.$set(targetProp.rate.low, 'total', { nightly_avg: newRate.low.total.nightly_avg, original_nightly_avg: newRate.low.total.original_nightly_avg }); }
方案4:用工具函数简化深层赋值(比如lodash.set)
如果项目里已经引入了lodash,直接用_.set能一行搞定深层属性赋值,不管属性是否存在:
updateRateData(targetProp, newRate) { _.set(targetProp, 'rate.low.total.nightly_avg', newRate.low.total.nightly_avg); _.set(targetProp, 'rate.low.total.original_nightly_avg', newRate.low.total.original_nightly_avg); }
不想引入lodash的话,也可以自己写个简单的深层赋值函数:
function setDeep(obj, path, value) { const keys = path.split('.'); let current = obj; for (let i = 0; i < keys.length - 1; i++) { if (!current[keys[i]]) current[keys[i]] = {}; current = current[keys[i]]; } current[keys[keys.length - 1]] = value; } // 使用示例 setDeep(targetProp, 'rate.low.total.nightly_avg', newRate.low.total.nightly_avg);
整合后的完整代码示例
把上面的优化点整合起来,你的Vue实例可以改成这样:
var properties = new Vue({ el: '#properties', data: { properties: [] }, mounted() { this.initData(); // 页面加载时初始化数据 }, methods: { async initData() { try { // 并行发起两个请求 const [viewRes, availableRes] = await Promise.all([ axios.get('/properties/view'), // 替换成你的view接口实际地址 axios.get(searchJs.getAttribute('webroot') + 'properties/available', { headers: {'Content-Type': 'application/json'} }) ]); this.properties = viewRes.data; this.updateAvailableData(availableRes.data); } catch (err) { console.error('数据加载失败:', err); } }, updateAvailableData(availableData) { const propMap = new Map(this.properties.map(p => [p.id, p])); availableData.forEach(p => { const targetProp = propMap.get(p.id); if (targetProp) { this.updateRateData(targetProp, p.rate); } }); }, updateRateData(targetProp, newRate) { // 这里选你喜欢的方案,比如直接赋值(假设结构已存在) targetProp.rate.low.total.nightly_avg = newRate.low.total.nightly_avg; targetProp.rate.low.total.original_nightly_avg = newRate.low.total.original_nightly_avg; // 或者用展开运算符 // targetProp.rate = { // ...targetProp.rate, // low: { // ...targetProp.rate.low, // total: { // ...targetProp.rate.low.total, // nightly_avg: newRate.low.total.nightly_avg, // original_nightly_avg: newRate.low.total.original_nightly_avg // } // } // }; } } });
这样既提升了数据加载和更新的效率,又简化了深层属性的写法,完全贴合Vue 2的最佳实践~
内容的提问来源于stack exchange,提问作者cnizzardini

