Vue 2 中产品评分绑定失效问题:为何 product.rating 在 console 正常却无法同步到 input 值?

问题描述:

在WordPress的Woocommerce自定义开发一个订单评论功能时,遇到了一个数据绑定的异常问题。具体场景如下:

1:打开评论弹窗时,通过openReviewModal(order)方法初始化数据:

深拷贝订单数据到currentOrder

为订单中的每个产品(currentOrder.items)动态添加rating和content字段并初始化

2:评分设置逻辑:

通过setRating(productId, rating)方法为指定产品设置评分

控制台打印product.rating时,能正常显示更新后的评分值

3:问题表现:

页面中使用<input type=”hidden” :name=”ratings[${product.id}]” :value=”product.rating”>绑定评分值

尽管console.log显示product.rating已正确更新,但 input 的value始终无法同步更新

具体原因:

Vue 2 的响应式系统是基于初始化时的属性劫持实现的。当通过 product.rating = 0 动态给对象添加属性时:

JavaScript 层面,product.rating 确实被创建并赋值了(所以 console.log 能打印正常);

但 Vue 没有 “监听” 到这个新属性的创建,因此当 setRating 方法修改 product.rating 时,Vue 不会触发视图更新(即 :value=”product.rating” 不会同步变化)。

解决方案1:用 this.$set 让属性具备响应性

初始化 rating 和 content 时,使用 Vue 提供的 this.$set 方法(专门用于给响应式对象动态添加响应式属性):

openReviewModal(order) {
  this.currentOrder = JSON.parse(JSON.stringify(order));
  
  // 关键修改:用 this.$set 初始化属性,确保响应性
  this.currentOrder.items.forEach(product => {
    // 第一个参数:目标对象;第二个参数:属性名;第三个参数:属性值
    this.$set(product, 'rating', 0); 
    this.$set(product, 'content', '');
  });
  
  this.isModalShow = true;
  document.body.style.overflow = 'hidden';
}

this.$set 会手动触发 Vue 的响应式系统,让新添加的 rating 和 content 属性被 Vue 监听。之后:

当 setRating 方法修改 product.rating 时,Vue 能感知到变化;

:value=”product.rating” 会自动同步更新,输入框的 value 会随数据变化而变化。

解决方案2:直接从后端传入rating和content值

在创建 order_list 数据时,就为每个 product 预先声明 rating 和 content 属性(即使值为空),确保 Vue 初始化时就能追踪它们:

// 在 PHP 生成 $order_list 时,提前为每个产品添加 rating 和 content 字段
$order_products[] = [
    'id' => $product->get_id(),
    'name' => $product_name,
    'variant' => $product_variant,
    'image' => $product_image_url,
    'rating' => 0, // 预先声明,初始值为 0
    'content' => '' // 预先声明,初始值为空
];

这样,Vue 初始化时会自动劫持这两个属性,后续修改时视图会正常响应。

注意:Vue 3 彻底解决了 Vue 2 中 “动态添加属性默认不响应” 的限制,这是由于 Vue 3 采用了全新的响应式系统实现方式 ——基于 Proxy(代理),而非 Vue 2 的 Object.defineProperty。

以上,该问题是 Vue 2 响应式系统的典型限制(动态添加的属性默认不响应),而非代码逻辑错误。通过 this.$set 初始化属性后,input 的 :value 就能正常同步 product.rating 的值了。