ListView值保存实现:切换品牌时留存商品数量输入数据
嗨,这个需求其实挺常见的,核心就是在切换品牌时把当前商品的输入值存起来,等下次切回来再回填就行。我给你准备了两种实现思路,一种是原生JavaScript的,另一种是Vue的(如果用框架的话会更省心),你可以根据自己的技术栈来选:
核心逻辑说明
不管用哪种方式,核心都是用一个存储对象来记录每个品牌下各商品的输入数量:
- 键可以按「品牌ID-商品ID」的格式,或者按品牌分组存储(后者更清晰)
- 切换品牌前,先把当前页面所有输入框的值存入存储对象
- 渲染新品牌的商品时,从存储对象里取出对应的值回填到输入框中
原生JavaScript实现示例
这种方案不需要依赖任何框架,直接用原生DOM操作就能完成:
1. HTML结构
<div class="container"> <div class="brand-list"> <h3>商品品牌</h3> <ul> <!-- 品牌列表通过JS动态生成 --> </ul> </div> <div class="product-list"> <h3>商品列表</h3> <div id="product-container"> <!-- 商品列表通过JS动态生成 --> </div> </div> </div>
2. 基础样式
.container { display: flex; gap: 20px; padding: 20px; } .brand-list { width: 200px; border-right: 1px solid #eee; } .brand-list ul { list-style: none; padding: 0; } .brand-list li { padding: 8px 12px; cursor: pointer; margin-bottom: 4px; border-radius: 4px; } .brand-list li.active { background-color: #007bff; color: white; } .product-item { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; } .product-item input { width: 60px; padding: 4px; }
3. 核心JS逻辑
// 模拟品牌数据 const brands = [ { id: 'brand1', name: '品牌A' }, { id: 'brand2', name: '品牌B' }, { id: 'brand3', name: '品牌C' } ]; // 模拟各品牌对应的商品 const brandProducts = { brand1: [ { id: 'prod1', name: '商品A1' }, { id: 'prod2', name: '商品A2' } ], brand2: [ { id: 'prod3', name: '商品B1' }, { id: 'prod4', name: '商品B2' } ], brand3: [ { id: 'prod5', name: '商品C1' } ] }; // 存储已输入的数量,结构:{ 品牌ID: { 商品ID: 数量值 } } const inputStorage = {}; let currentBrandId = null; // 获取DOM元素 const brandListEl = document.querySelector('.brand-list ul'); const productContainerEl = document.getElementById('product-container'); // 初始化品牌列表 function initBrandList() { brands.forEach(brand => { const li = document.createElement('li'); li.textContent = brand.name; li.dataset.brandId = brand.id; li.addEventListener('click', () => switchBrand(brand.id)); brandListEl.appendChild(li); }); // 默认选中第一个品牌 brands.length > 0 && switchBrand(brands[0].id); } // 切换品牌的核心函数 function switchBrand(brandId) { // 1. 先保存当前品牌的输入值(如果有当前品牌) currentBrandId && saveCurrentBrandInputs(currentBrandId); // 2. 更新当前品牌状态并高亮选中项 currentBrandId = brandId; document.querySelectorAll('.brand-list li').forEach(li => { li.classList.toggle('active', li.dataset.brandId === brandId); }); // 3. 渲染新品牌的商品并回填存储的值 renderProducts(brandId); } // 保存当前品牌的输入值 function saveCurrentBrandInputs(brandId) { if (!inputStorage[brandId]) inputStorage[brandId] = {}; const inputEls = document.querySelectorAll('.product-item input'); inputEls.forEach(input => { const productId = input.dataset.productId; inputStorage[brandId][productId] = input.value.trim() || ''; }); // 可选:存入localStorage实现页面刷新不丢失数据 localStorage.setItem('productInputStorage', JSON.stringify(inputStorage)); } // 渲染商品列表 function renderProducts(brandId) { const products = brandProducts[brandId] || []; productContainerEl.innerHTML = ''; products.forEach(product => { const productItem = document.createElement('div'); productItem.className = 'product-item'; // 从存储中取已保存的值,没有则为空 const savedValue = inputStorage[brandId]?.[product.id] || ''; productItem.innerHTML = ` <span>${product.name}</span> <input type="number" min="0" data-product-id="${product.id}" value="${savedValue}"> `; productContainerEl.appendChild(productItem); }); } // 初始化时从localStorage读取已保存的数据(可选) const savedStorage = localStorage.getItem('productInputStorage'); savedStorage && Object.assign(inputStorage, JSON.parse(savedStorage)); // 启动初始化 initBrandList();
Vue.js实现示例(更简洁)
如果你的项目用Vue框架,借助响应式数据可以更轻松地实现,不需要手动操作DOM:
<template> <div class="container"> <div class="brand-list"> <h3>商品品牌</h3> <ul> <li v-for="brand in brands" :key="brand.id" :class="{ active: currentBrandId === brand.id }" @click="switchBrand(brand.id)" > {{ brand.name }} </li> </ul> </div> <div class="product-list"> <h3>商品列表</h3> <div class="product-item" v-for="product in currentProducts" :key="product.id" > <span>{{ product.name }}</span> <input type="number" min="0" v-model="inputStorage[currentBrandId][product.id]" > </div> </div> </div> </template> <script> export default { data() { return { brands: [ { id: 'brand1', name: '品牌A' }, { id: 'brand2', name: '品牌B' }, { id: 'brand3', name: '品牌C' } ], brandProducts: { brand1: [ { id: 'prod1', name: '商品A1' }, { id: 'prod2', name: '商品A2' } ], brand2: [ { id: 'prod3', name: '商品B1' }, { id: 'prod4', name: '商品B2' } ], brand3: [ { id: 'prod5', name: '商品C1' } ] }, currentBrandId: 'brand1', inputStorage: {} } }, computed: { // 计算当前品牌对应的商品列表 currentProducts() { return this.brandProducts[this.currentBrandId] || []; } }, created() { // 初始化存储结构 this.brands.forEach(brand => { this.$set(this.inputStorage, brand.id, {}); // 给每个商品初始化空值 this.brandProducts[brand.id]?.forEach(prod => { this.$set(this.inputStorage[brand.id], prod.id, ''); }); }); // 可选:从localStorage读取已保存的数据 const savedStorage = localStorage.getItem('productInputStorage'); savedStorage && Object.assign(this.inputStorage, JSON.parse(savedStorage)); }, methods: { switchBrand(brandId) { // 因为用了v-model,数据已经实时同步到inputStorage,直接切换即可 this.currentBrandId = brandId; } }, watch: { // 监听存储变化,自动保存到localStorage(可选) inputStorage: { deep: true, handler(val) { localStorage.setItem('productInputStorage', JSON.stringify(val)); } } } } </script> <style scoped> .container { display: flex; gap: 20px; padding: 20px; } .brand-list { width: 200px; border-right: 1px solid #eee; } .brand-list ul { list-style: none; padding: 0; } .brand-list li { padding: 8px 12px; cursor: pointer; margin-bottom: 4px; border-radius: 4px; } .brand-list li.active { background-color: #007bff; color: white; } .product-item { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; } .product-item input { width: 60px; padding: 4px; } </style>
内容的提问来源于stack exchange,提问作者Александр Волошиновский
相关产品推荐
相关产品推荐

