Laravel中Vue组件@click.stop事件无法触发问题求助
Laravel Vue组件@click.stop事件无法触发排查
问题描述
- Laravel项目中Vue组件内所有
@click.stop事件完全无法触发 - 已执行
npm run watch并清理缓存,控制台仅存在一个无关错误:
Uncaught TypeError: document.getElementById(...) is null <anonymous> http://127.0.0.1:8000/back-assets/js/index2.js:121 jQuery 2
核心排查点
- Vue挂载根元素检查:确认Blade模板中存在
id="app"的根容器,<attribute-values>组件必须在该容器内部才能被Vue实例接管。 - 组件挂载时机:将
@push('scripts')移到页面底部,或给script标签添加defer属性,确保Vue实例在DOM渲染完成后初始化。 - 事件修饰符排查:暂时移除
.stop修饰符,测试基础@click是否能触发,排查外层元素的事件阻止冒泡逻辑干扰。 - Vue版本一致性:当前package.json中
vue版本为2.5.17,vue-template-compiler为2.6.10,版本不一致可能导致编译异常,需将两者统一为同一版本(如2.6.x)。 - 组件注册验证:在浏览器控制台执行
Vue.options.components['attribute-values'],确认组件已正确注册。 - 无关错误修复:虽然错误来自
index2.js,但JS执行错误会阻断后续代码,建议先修复document.getElementById找不到元素的问题,再测试Vue事件。
相关代码
app.js代码
window._ = require("lodash"); // window.Vue = require('vue'); import Vue from "vue"; window.axios = require("axios"); window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest"; let token = document.head.querySelector('meta[name="csrf-token"]'); if (token) { window.axios.defaults.headers.common["X-CSRF-TOKEN"] = token.content; } else { console.error( "CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token" ); } // const files = require.context('./', true, /\.vue$/i); // files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default)); import VueSwal from "vue-swal"; Vue.use(VueSwal); Vue.component( "example-component", require("./components/ExampleComponent.vue").default ); //Vue.component('product-attributes', require('./components/ProductAttributes').default); Vue.component( "attribute-values", require("./components/AttributeValues.vue").default ); const app = new Vue({ el: "#app", });
AttributeValues.vue代码
<template> <div id=""> <div class="tile"> <h3 class="tile-title">Attribute Values</h3> <hr /> <div class="tile-body"> <div class="form-group"> <label class="control-label" for="value">Value</label> <input class="form-control" type="text" placeholder="Enter attribute value" id="value" name="value" v-model="value" /> </div> <div class="form-group"> <label class="control-label" for="price">Price</label> <input class="form-control" type="number" placeholder="Enter attribute value price" id="price" name="price" v-model="price" /> </div> </div> <div class="tile-footer"> <div class="row d-print-none mt-2"> <div class="col-12 text-right"> <button class="btn btn-success" type="submit" @click.stop="saveValue()" v-if="addValue" > <i class="fa fa-fw fa-lg fa-check-circle"></i>Save </button> <button class="btn btn-success" type="submit" @click.stop="updateValue()" v-if="!addValue" > <i class="fa fa-fw fa-lg fa-check-circle"></i>Update </button> <button class="btn btn-primary" type="submit" @click.stop="reset()" v-if="!addValue" > <i class="fa fa-fw fa-lg fa-check-circle"></i>Reset </button> </div> </div> </div> </div> <div class="tile"> <h3 class="tile-title">Option Values</h3> <div class="tile-body"> <div class="table-responsive"> <table class="table table-sm"> <thead> <tr class="text-center"> <th>#</th> <th>Value</th> <th>Price</th> <th>Action</th> </tr> </thead> <tbody> <tr v-for="value in values"> <td style="width: 25%" class="text-center">{{ value.id }}</td> <td style="width: 25%" class="text-center"> {{ value.value }} </td> <td style="width: 25%" class="text-center"> {{ value.price }} </td> <td style="width: 25%" class="text-center"> <button class="btn btn-sm btn-primary" @click.stop="editAttributeValue(value)" > <i class="fa fa-edit"></i> </button> <button class="btn btn-sm btn-danger" @click.stop="deleteAttributeValue(value)" > <i class="fa fa-trash"></i> </button> </td> </tr> </tbody> </table> </div> </div> </div> </div> </template> <script type="application/javascript"> export default { name: "attribute-values", props: ["attributeid"], data() { return { values: [], value: "", price: "", currentId: "", addValue: true, key: 0, }; }, created: function () { this.loadValues(); }, methods: { loadValues() { let attributeId = this.attributeid; let _this = this; axios .post("/admin/attributes/get-values", { id: attributeId, }) .then(function (response) { _this.values = response.data; }) .catch(function (error) { console.log(error); }); }, saveValue() { if (this.value === "") { this.$swal("Error, Value for attribute is required.", { icon: "error", }); } else { let attributeId = this.attributeid; let _this = this; axios .post("/admin/attributes/add-values", { id: attributeId, value: _this.value, price: _this.price, }) .then(function (response) { _this.values.push(response.data); _this.resetValue(); _this.$swal("Success! Value added successfully!", { icon: "success", }); }) .catch(function (error) { console.log(error); }); } }, resetValue() { this.value = ""; this.price = ""; }, reset() { this.addValue = true; this.resetValue(); }, editAttributeValue(value) { this.addValue = false; this.value = value.value; this.price = value.price; this.currentId = value.id; this.key = this.values.indexOf(value); }, updateValue() { if (this.value === "") { this.$swal("Error, Value for attribute is required.", { icon: "error", }); } else { let attributeId = this.attributeid; let _this = this; axios .post("/admin/attributes/update-values", { id: attributeId, value: _this.value, price: _this.price, valueId: _this.currentId, }) .then(function (response) { _this.values.splice(_this.key, 1); _this.resetValue(); _this.values.push(response.data); _this.$swal("Success! Value updated successfully!", { icon: "success", }); }) .catch(function (error) { console.log(error); }); } }, deleteAttributeValue(value) { this.$swal({ title: "Are you sure?", text: "Once deleted, you will not be able to recover this attribute value!", icon: "warning", buttons: true, dangerMode: true, }).then((willDelete) => { if (willDelete) { this.currentId = value.id; this.key = this.values.indexOf(value); let _this = this; axios .post("/admin/attributes/delete-values", { id: _this.currentId, }) .then(function (response) { if (response.data.status === "success") { _this.values.splice(_this.key, 1); _this.resetValue(); _this.$swal("Success! Option value has been deleted!", { icon: "success", }); } else { _this.$swal("Your option value not deleted!"); } }) .catch(function (error) { console.log(error); }); } else { this.$swal("Your option value not deleted!"); } }); }, }, }; </script>
Blade模板代码
<div class="tab-pane" id="values"> <attribute-values :attributeid="{{ $attribute->id }}"></attribute-values> </div> @endsection @push('scripts') <script type="application/javascript" src="{{ asset('js/app.js') }}"> </script> @endpush
composer.json配置
{ "name": "laravel/laravel", "type": "project", "description": "The Laravel Framework.", "keywords": ["framework", "laravel"], "license": "MIT", "require": { "php": "^7.3|^8.0", "fruitcake/laravel-cors": "^2.0", "guzzlehttp/guzzle": "^7.0.1", "laravel/framework": "^8.75", "laravel/helpers": "^1.5", "laravel/sanctum": "^2.11", "laravel/tinker": "^2.5", "laravel/ui": "^2.0", "typicms/nestablecollection": "*" }, "require-dev": { "facade/ignition": "^2.5", "fakerphp/faker": "^1.9.1", "laravel/sail": "^1.0.1", "mockery/mockery": "^1.4.4", "nunomaduro/collision": "^5.10", "phpunit/phpunit": "^9.5.10" }, "autoload": { "psr-4": { "App": "app/", "Database\\Factories": "database/factories/", "Database\\Seeders": "database/seeders/" } }, "autoload-dev": { "psr-4": { "Tests": "tests/" } }, "scripts": { "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "@php artisan package:discover --ansi" ], "post-update-cmd": [ "@php artisan vendor:publish --tag=laravel-assets --ansi --force" ], "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], "post-create-project-cmd": ["@php artisan key:generate --ansi"] }, "extra": { "laravel": { "dont-discover": [] } }, "config": { "optimize-autoloader": true, "preferred-install": "dist", "sort-packages": true }, "minimum-stability": "dev", "prefer-stable": true }
package.json配置
{ "private": true, "scripts": { "dev": "npm run development", "development": "mix", "watch": "mix watch", "watch-poll": "mix watch -- --watch-options-poll=1000", "hot": "mix watch --hot", "prod": "npm run production", "production": "mix --production" }, "devDependencies": { "axios": "^0.21", "bootstrap": "^4.0.0", "cross-env": "^5.1", "jquery": "^3.2", "laravel-mix": "^6.0.43", "lodash": "^4.17.19", "popper.js": "^1.12", "postcss": "^8.1.14", "resolve-url-loader": "^2.3.1", "sass": "^1.20.1", "sass-loader": "^8.0.0", "vue": "^2.5.17", "vue-loader": "^15.9.7", "vue-template-compiler": "^2.6.10" }, "dependencies": { "vue-swal": "^0.1.0" } }
内容的提问来源于stack exchange,提问作者Wanjila Abraham
相关产品推荐
相关产品推荐

