【问题标题】:Vuejs + onClick doesn't work on dynamic element loaded after mountedVuejs + onClick 在安装后加载的动态元素上不起作用
【发布时间】:2022-07-14 14:01:06
【问题描述】:

我被这个问题困住了。当我点击某个元素时,它会将一个项目推送到一个数组中,然后我在一个表中显示这个数组。我想添加一个操作以这种方式删除表格的任何行,例如: Table

我的代码:

<div id="pos">
<div class="container-fluid" style="font-size: 0.8em;">
    <div class="row grid-columns">
        <div class="col-md-6 col">
            <table class="table">
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Descripcion</th>
                        <th>Stock</th>
                        <th>Precio uni</th>
                        <th>Precio alt</th>
                        <th>Cant</th>
                        <th>Subtotal</th>
                        <th>Acciones</th>
                    </tr>
                </thead>
                <tbody>
                    <pos-products
                        :products="products"
                        v-on:remove-product="removeProduct"
                    >
                    </pos-products>
                    <!-- <tr v-for="item in products" :key="item.id">
                        <th scope="row">${item.id}</th>
                        <td>${ item.descripcion }</td>
                        <td>${ item.stock }</td>
                        <td>${ item.precio } $</td>
                        <td>${ item.precio_alt } $</td>
                        <td>
                            <v-minusplusfield :value="1" :min="1" :max="100" v-model="item.cant"></v-minusplusfield>
                        </td>
                        <td>${ getSubtotal(item) }</td>
                        <td><a href="#" @click="removeItem(item)"> Borrar </a></td>
                    </tr> -->
                </tbody>
            </table>
        </div>
        <div class="col-md-6 col">
            <div>
                <div id="grid-header" class="p-2 border-b ">
                    <input class="form-control" name="searchString" placeholder="Buscar producto" type="text" v-model="searchString" />
                </div>
            </div>
            <div style="background-color:#fff">
                <div class="col-md-3" v-for="item in searchResults">
                    <a
                        href="#"
                        class="list-group-item"
                        :key="item.id"
                        @click="loadItem(item)"
                    >
                        <img src="//images03.nicepage.com/a1389d7bc73adea1e1c1fb7e/af4ca43bd20b5a5fab9f188a/pexels-photo-3373725.jpeg" alt="" class="u-expanded-width u-image u-image-default u-image-1" width="25" height="30">
                        <h6 class="u-text u-text-default u-text-1">${item.descripcion}</h6>
                        <h4 class="u-text u-text-default u-text-2">${item.precio}$ / ${item.precio_alt}$</h4>
                    </a>
                </div>
            </div>
        </div>
    </div>
</div>

Vue 代码:

const app = new Vue({
el: "#pos",
delimiters: ["${", "}"],
data () {
    return {
        products: [],
        total: 0,
        client: "",
        user: "",
        paymentDetail: [],
        errors: {},
        garantia: false,
        saveButton: false,
        seller: "",
        searchString: "",
        searchTypingTimeout: "",
        searchResults: [],
    }
},
methods: {
    getSubtotal: function (item) {
        return parseInt(item.cant) * parseFloat(item.precio);
    },
    loadItem: function (item) {
        this.products.push({
            id: item.id,
            descripcion: item.descripcion,
            stock: item.stock,
            precio: item.precio,
            precio_alt: item.precio_alt,
            cant: 1,
        });
    },
    removeItem: () => {
        products = products.filter((el) => el !== item);
    },
    searchProducts: function (value) {
        axios
            .post("/v2/producto/search", {
                query: value
            })
            .then((response) => {
                if (!response.status == 200 || response.data.error) {
                    console.log('error')
                    const errorMessage = response.data.error
                        ? response.data.error
                        : "Ha ocurrido un error";
                    console.log("mensaje: " + errorMessage);
                    this.$swal({
                        icon: "error",
                        title: "Oops...",
                        text: errorMessage,
                    });
                    return;
                }
                this.searchResults = response.data.data;
            })
            .catch((error) => {
                console.log("catch error", error);
            });
    },
},
mounted() {
    var csrf = document
        .querySelector('meta[name="csrf-token"]')
        .getAttribute("content");
    this.products = [];
},
computed: {},
watch: {
    total(val) {
        this.total = parseFloat(val);
    },
    searchString(val) {
        if (this.searchTypingTimeout) clearTimeout(this.searchTypingTimeout);
        this.searchTypingTimeout = setTimeout(
            () => this.searchProducts(this.searchString),
            850
        );
    },
},

});

我知道了:

vue.js?3de6:634 [Vue 警告]:属性或方法“removeItem”未在实例上定义,但在渲染期间被引用。通过初始化该属性,确保此属性是反应性的,无论是在数据选项中,还是对于基于类的组件。见:https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties。

【问题讨论】:

  • 如果你在removeItem()方法中使用的products是vue data,我认为你必须使用this.products。此外,您发布的代码不完整,其他人可能会产生相同的错误,例如不清楚 loadItem() 方法在何时何地被调用?

标签: vue.js


【解决方案1】:

尝试使用这样的经典功能:

removeItem(item){
   const index = this.items.findIndex(x => x.id === item.id)
   this.items.splice(index, 1)
},

我在这里用jsonplaceholder.typicode.com api加载了数据

new Vue({
      el: '#app',
      data: () => ({
        items: []
      }),
      
      async mounted(){
        await axios.get('https://jsonplaceholder.typicode.com/posts')
        .then(res => {
          this.items = res.data
        })
      },
      
      methods: {
        removeItem(item){
          const index = this.items.findIndex(x => x.id === item.id)
          this.items.splice(index, 1)
        },
      }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.27.2/axios.min.js" integrity="sha512-odNmoc1XJy5x1TMVMdC7EMs3IVdItLPlCeL5vSUPN2llYKMJ2eByTTAIiiuqLg+GdNr9hF6z81p27DArRFKT7A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div id="app">

<h1>List </h1>
  <ul>
    <li v-for="item of items" :key="item.id">
      <a @click="removeItem(item)">{{item.id}} - {{item.title}}</a>
    </li>
  </ul>
</div>

【讨论】:

  • 谢谢,但是这些项目是在 loadItem 方法上动态加载的,该方法将项目推送到 products 数组中
  • 您的解决方案没问题,但在我的情况下,我通过单击搜索结果来附加项目。这是演示视频:files.fm/u/a6xyzdqxv
  • 您获取数据的方式似乎很有效,我们正在研究如何删除这些数据。您是否也尝试编写与使用 removeItem: function (item) { 之类的 loadItem 相同的函数?
  • 你能看看这里吗? jsfiddle.net/eqj05a6L/9 就是这种情况。我需要的是从 dom 之后加载的元素调用方法
  • 在这段代码中,只需将模板中的removeItem替换为removeProduct,代码就可以完美运行:) (&lt;td&gt;&lt;a href="#" @click="removeProduct(item)"&gt; Delete item &lt;/a&gt;&lt;/td&gt;)
猜你喜欢
  • 2017-02-13
  • 2013-10-28
  • 2019-03-15
  • 1970-01-01
  • 2018-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
相关资源
最近更新 更多