Vue.js 2动态添加表格行无法应用data属性值与CSS样式
解决Vue动态添加表格行无法绑定数据与样式的问题
Hey there, let's break down why your dynamically added rows aren't working as expected, and fix it the Vue way.
问题根源
你现在用原生JS直接插入DOM的方式有两个致命问题:
- Vue不会编译动态插入的HTML:你插入的
<select>里的v-for、v-bind这些Vue指令,Vue根本不会识别和编译,所以chargesOpt里的选项完全渲染不出来。 - Scoped样式无法作用于动态DOM:你的
<style>加了scoped,Vue会给所有组件内的模板元素添加一个专属属性(比如data-v-xxxxxx),动态插入的DOM没有这个属性,所以你的form-control3等样式无法生效。
正确解决方案:用Vue响应式数据驱动表格行
Vue的核心是数据驱动视图,我们不需要手动操作DOM,只需要用一个响应式数组存储所有行的数据,通过v-for渲染即可。新增行时只需要往数组里推一条数据,Vue会自动帮我们完成DOM更新、指令编译和样式应用。
修改后的完整代码:
<template> <b-card id="showBill"> <div class="table-responsive col-md-6"> <table class="table table-striped table-bordered table-sm" id="tbl"> <thead> <tr> <th>Charges</th> <th>Amount</th> </tr> </thead> <tbody> <!-- 用v-for渲染所有行,绑定唯一key值 --> <tr v-for="(row, index) in billRows" :key="index"> <td> <select class="form-control input-sm form-control3"> <option v-for="option in chargesOpt" :value="option.value" :key="option.value"> {{ option.text }} </option> </select> </td> <td> <!-- 用v-model绑定行的金额数据,方便后续计算总和 --> <input type="text" class="form-control input-sm form-control3" v-model="row.amount"> </td> </tr> </tbody> <tfoot> <tr class="table-secondary"> <th>Total Amount</th> <!-- 实时计算总金额 --> <th style="text-align:right;">{{ totalAmount.toFixed(2) }}</th> </tr> </tfoot> </table> </div> <div class="col-md-6"> <button type="button" class="btn btn-success" @click="addRow">Add</button> </div> </b-card> </template> <script> export default { data () { return { chargesOpt:[ { value: '', text: 'Select'}, { value: '1', text: 'Maintanence'}, { value: '2', text: 'Extra'} ], // 用响应式数组存储所有行数据,初始默认一条空行 billRows: [{ amount: '' }] } }, computed: { // 计算属性实时计算总金额,自动响应数据变化 totalAmount() { return this.billRows.reduce((sum, row) => { const amount = parseFloat(row.amount) || 0 return sum + amount }, 0) } }, methods:{ addRow() { // 新增行只需往数组push一条空数据,Vue自动渲染新行 this.billRows.push({ amount: '' }) } } } </script> <style lang="scss" scoped> @import '../../../node_modules/bootstrap/dist/css/bootstrap.min.css'; .is-danger{ color: RED; } .form-control{display:block;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;box-shadow:inset 0 1px 1px rgba(0,0,0,.075);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out } .input-sm{ border: 1px solid #ccc; padding: 5px 8px; color: #616161; background: #fff; box-shadow: none !important; width: 100%; font-size: 0.85em; font-weight: 300; height: 40px; border-radius: 0; -webkit-appearance: none; resize: none; } .input-sm { font-size: 14px; height: 35px; } .form-control3 { /* For Vacancy List Table Input Fields */ padding-bottom: 0px; padding-top: 0px; background-color: transparent!important; background: transparent !important; border: 1px solid transparent !important; border-radius: 5px; box-shadow: none !important; } .form-control3:focus { border: 1px solid #03a9f4 !important; background: #fff !important; box-shadow: none !important; } .form-control3{ height: 30px; } .form-control3{ padding-bottom: 0px; padding-top: 0px; } </style>
方案优势
- 数据与视图自动同步:所有行的渲染、更新都由响应式数组驱动,无需手动操作DOM,彻底避免指令不生效的问题。
- Scoped样式正常作用:新行是Vue通过模板渲染的,会自动带上scoped样式所需的专属属性,样式完美生效。
- 可扩展性更强:新增了总金额计算功能,后续如果需要删除行、校验数据等,只需要操作
billRows数组即可,代码更易维护。
不推荐的原生DOM方案(仅作参考)
如果你非要用原生JS插入行,需要解决两个问题:
- 手动编译Vue模板:用
Vue.compile编译插入的HTML片段,再挂载到目标元素上,但这会增加代码复杂度,违背Vue的设计思想。 - 穿透Scoped样式:把需要作用于动态元素的样式移出
scoped,或者用::v-deep .form-control3强制穿透,但这会扩大样式作用范围,可能引发样式冲突。
还是强烈建议用响应式数组的方案,这是Vue开发的最佳实践。
内容的提问来源于stack exchange,提问作者Ashwini




