Error in v-on handler: "TypeError: val.join is not a function"

本文解决了一个JavaScript中的常见错误:TypeError,具体为val.join不是函数的问题。通过分析代码片段,指出了使用字符串比较时的正确做法。

Error in v-on handler: "TypeError: val.join is not a function

小错误。。(不喜忽喷!)

遇到问题上来优快云搜一下,但是找到的答案不是自己需要的,看了老半天,还是自己粗心大意造成的小失误,

浏览器F12中控制台显示的错误
Error in v-on handler: "TypeError: val.join is not a function,val.join没有起作用,我查看相关代码,
Error in v-on handler: "TypeError: val.join is not a function,说明val.join没有起作用,我查看相关代码,

if (val.join() == ‘A业务’) {
this.serviceType = null;
} else if (val.join() == ‘PB业务’) {
this.serviceType = 1;
} else if (val.join() == ‘C业务’) {
this.serviceType = 2;
} else if (val.join() == ‘D业务’) {
this.serviceType = 3;
} else if (val.join() == ‘E业务’) {
this.serviceType = 4;
}

在.vue单文件中 data里面的属性和methods里面的方法不存在重名,

错误:
上面代码中的判断语句中的val.join()==’ * ’ ,
应该写成val.join == ’ * '

// @ts-nocheck class SweetalertSystem { constructor() { this.fieldRegistry = {}; this.modalRegistry = {}; // 添加模态类型注册表 this.nestedModalStack = []; // 添加嵌套模态栈 this.initCoreComponents(); // 初始化事件处理器映射 this.buttonHandlers = new Map(); this.addEntityButtons = null; } initCoreComponents() { // 注册核心字段类型 this.registerFieldType('text', { render: (config) => { return `<div class="mb-3"> <label class="form-label">${config.label}${config.required ? '*' : ''}</label> <input type="text" class="form-control" name="${config.name}" value="${config.value || ''}" ${config.required ? 'required' : ''} placeholder="${config.placeholder || ''}"> </div>`; } }); this.registerFieldType('select', { render: (config) => { const options = (config.options || []) .map(opt => `<option value="${opt.value}" ${config.value == opt.value ? 'selected' : ''}>${opt.label}</option>`) .join(''); return `<div class="mb-3"> <label class="form-label">${config.label}${config.required ? '*' : ''}</label> <div class="input-group"> <select class="form-select" name="${config.name}" ${config.required ? 'required' : ''}> <option value="">${config.placeholder || '请选择'}</option> ${options} </select> ${config.addButton ? ` <button class="btn btn-outline-secondary add-entity-btn" type="button" data-target-field="${config.name}"> <i class="fa fa-plus"></i> ${config.addButton.label} </button> ` : ''} </div> </div>`; }, // 更新 afterRender 方法 afterRender: (element, config) => { if (config.select2) { const $select = $(element).find('select'); const swalContainer = Swal.getContainer(); this.safeInitSelect2($select, { theme: 'bootstrap', placeholder: config.placeholder || '请选择', allowClear: true, dropdownParent: swalContainer || document.body }); } } }); this.registerFieldType('number', { render: (config) => { return `<div class="mb-3"> <label class="form-label">${config.label}${config.required ? '*' : ''}</label> <input type="number" class="form-control" name="${config.name}" value="${config.value || ''}" ${config.required ? 'required' : ''} step="${config.step || 1}" min="${config.min || 0}"> </div>`; } }); this.registerFieldType('checkbox', { render: (config) => { return `<div class="mb-3 form-check"> <input type="checkbox" class="form-check-input" name="${config.name}" id="${config.name}" ${config.value ? 'checked' : ''}> <label class="form-check-label" for="${config.name}">${config.label}</label> </div>`; } }); } // 修改注册方法 - 接受对象而不是函数 registerFieldType(type, definition) { if (!definition.render || typeof definition.render !== 'function') { throw new Error(`Field type '${type}' must have a render function`); } this.fieldRegistry[type] = definition; } // === 字段渲染方法 === renderTextField(config) { return `<div class="mb-3"> <label class="form-label">${config.label}${config.required ? '*' : ''}</label> <input type="text" class="form-control" name="${config.name}" value="${config.value || ''}" ${config.required ? 'required' : ''} placeholder="${config.placeholder || ''}"> </div>`; } renderSelectField(config) { const options = (config.options || []) .map(opt => `<option value="${opt.value}" ${config.value == opt.value ? 'selected' : ''}>${opt.label}</option>`) .join(''); return `<div class="mb-3"> <label class="form-label">${config.label}${config.required ? '*' : ''}</label> <div class="input-group"> <select class="form-select" name="${config.name}" ${config.required ? 'required' : ''}> <option value="">${config.placeholder || '请选择'}</option> ${options} </select> ${config.addButton ? ` <button class="btn btn-outline-secondary add-entity-btn" type="button" data-target-field="${config.name}"> <i class="fa fa-plus"></i> ${config.addButton.label} </button> ` : ''} </div> </div>`; } renderNumberField(config) { return `<div class="mb-3"> <label class="form-label">${config.label}${config.required ? '*' : ''}</label> <input type="number" class="form-control" name="${config.name}" value="${config.value || ''}" ${config.required ? 'required' : ''} step="${config.step || 1}" min="${config.min || 0}"> </div>`; } renderCheckboxField(config) { return `<div class="mb-3 form-check"> <input type="checkbox" class="form-check-input" name="${config.name}" id="${config.name}" ${config.value ? 'checked' : ''}> <label class="form-check-label" for="${config.name}">${config.label}</label> </div>`; } // === 核心方法 ===// === 核心方法 === /** * 打开表单弹窗(支持多个新建按钮) * @param {Object} config - 配置对象 */ async openForm(config) { const { title, fields, onSubmit, onAddEntity } = config; // 生成表单HTML const formHTML = fields.map(fieldConfig => { if (!fieldConfig.type) return '<div class="error">Missing field type</div>'; const fieldType = this.fieldRegistry[fieldConfig.type]; if (!fieldType) return `<div class="error">Field type '${fieldConfig.type}' not supported</div>`; return fieldType.render(fieldConfig); }).join(''); // 创建弹窗 return new Promise((resolve) => { Swal.fire({ title, html: `<form>${formHTML}</form>`, focusConfirm: false, showCancelButton: true, confirmButtonText: config.confirmButtonText || '保存', cancelButtonText: config.cancelButtonText || '取消', preConfirm: () => this.collectFormData(), // ... 配置 ... didOpen: () => { // 使用 MutationObserver 确保 DOM 完全渲染 const observer = new MutationObserver(() => { if (Swal.getPopup().querySelectorAll('.add-entity-btn').length > 0) { observer.disconnect(); this.setupMultiButtonHandlers(config, onAddEntity); } }); observer.observe(Swal.getPopup(), { childList: true, subtree: true }); }, willClose: () => { this.cleanupMultiButtonHandlers(); this.destroyAllSelect2(); // 确保清理所有 Select2 实例 } }).then((result) => { if (result.isConfirmed) { onSubmit(result.value); resolve(true); } else { resolve(false); } }); }); } collectFormData() { const data = {}; const popup = Swal.getPopup(); const form = popup.querySelector('form'); if (form) { const formData = new FormData(form); for (const [name, value] of formData.entries()) { // 处理多值字段 if (data[name]) { if (!Array.isArray(data[name])) { data[name] = [data[name]]; } data[name].push(value); } else { data[name] = value; } } } return data; } setupEventHandlers(config) { const popup = Swal.getPopup(); // 绑定添加按钮事件 popup.querySelectorAll('.add-entity-btn').forEach(btn => { btn.addEventListener('click', async () => { const targetField = btn.dataset.targetField; if (config.onAddEntity) { const newItem = await config.onAddEntity(targetField); if (newItem) { this.updateSelectField(popup, targetField, newItem); } } }); }); } // === 模态框注册方法 === registerModalType(name, config) { // 添加afterRender处理 const enhancedConfig = { ...config, afterRender: (config, container) => { // 初始化Select2 container.find('.select2-field').each(function() { const $select = $(this); $select.select2({ theme: 'bootstrap', placeholder: $select.attr('placeholder') || '请选择', allowClear: true, dropdownParent: $select.closest('.modal') }); }); // 调用原始afterRender(如果存在) if (config.afterRender) { config.afterRender(config, container); } } }; this.modalRegistry[name] = enhancedConfig; } // 注册实体表单 registerEntityForm(entityType, fields) { this.registerModalType(entityType, { template: `<div class="modal fade" id="${entityType}Modal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="${entityType}Title"></h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body" id="${entityType}Body"></div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button> <button type="button" class="btn btn-primary" id="${entityType}Submit">保存</button> </div> </div> </div> </div>`, render: (config, container) => { container.find(`#${entityType}Title`).text(config.title); let formHTML = ''; // 确保fields是数组 const fields = Array.isArray(config.fields) ? config.fields : []; fields.forEach(fieldConfig => { const fieldType = this.fieldRegistry[fieldConfig.type]; if (fieldType && fieldType.render) { formHTML += fieldType.render(fieldConfig); } }); container.find(`#${entityType}Body`).html(formHTML); }, getFormData: (container) => { const formData = {}; container.find('input, select, textarea').each(function() { const $el = $(this); const name = $el.attr('name'); if (!name) return; if ($el.attr('type') === 'checkbox') { formData[name] = $el.is(':checked'); } else { formData[name] = $el.val(); } }); return formData; }, bindEvents: (config, container, onSubmit) => { container.find(`#${entityType}Submit`).off('click').on('click', () => { const formData = this.getFormData(container); onSubmit(formData); }); } }); } // 打开模态框 open(modalType, config, callbacks = {}) { // 如果当前有激活的弹窗,先隐藏它 if (this.nestedModalStack.length > 0) { const currentModal = this.nestedModalStack[this.nestedModalStack.length - 1]; currentModal.hide(); } // 检查模态类型是否注册 if (!this.modalRegistry[modalType]) { console.error(`未注册的模态类型: ${modalType}`); return null; } const modalConfig = this.modalRegistry[modalType]; const modalId = `${modalType}Modal`; let $modal = $(`#${modalId}`); // 如果模态框不存在则创建 if ($modal.length === 0) { $modal = $(modalConfig.template); $('body').append($modal); } // 清除之前的模态框实例 if ($modal.data('bs.modal')) { $modal.data('bs.modal').dispose(); } // 渲染模态内容 modalConfig.render(config, $modal); // 绑定事件 if (modalConfig.bindEvents) { modalConfig.bindEvents(config, $modal, callbacks.onSubmit || (() => {})); } // 创建模态实例 const modalInstance = new bootstrap.Modal($modal[0]); // 执行afterRender回调 if (modalConfig.afterRender) { modalConfig.afterRender(config, $modal); } // 初始化Select2 $modal.find('.select2-field').each(function() { const $select = $(this); $select.select2({ theme: 'bootstrap', placeholder: $select.attr('placeholder') || '请选择', allowClear: true, dropdownParent: $select.closest('.modal') }); }); // 显示弹窗 modalInstance.show(); // 将新弹窗加入栈 const modalObj = { hide: () => modalInstance.hide(), show: () => modalInstance.show(), getElement: () => $modal[0], config }; this.nestedModalStack.push(modalObj); // 使用延迟确保 DOM 完全渲染 setTimeout(() => { // 安全初始化 Select2 $modal.find('.select2-field').each((index, element) => { const $select = $(element); this.safeInitSelect2($select, { theme: 'bootstrap', placeholder: $select.attr('placeholder') || '请选择', allowClear: true, dropdownParent: $modal }); }); // 绑定新建按钮事件 $modal.find('.add-entity-btn').on('click', async () => { const entityType = $(this).data('entityType'); const targetField = $(this).data('targetField'); if (callbacks.onAddEntity) { const newItem = await callbacks.onAddEntity(entityType, targetField); if (newItem) { this.updateSelectField($modal[0], targetField, newItem); } } }); }, 50); // 返回包含关闭方法的实例对象 return modalObj; } // 关闭当前弹窗并显示上一个 closeCurrentModal() { if (this.nestedModalStack.length > 0) { const currentModal = this.nestedModalStack.pop(); currentModal.hide(); // 如果有上一个弹窗,显示它 if (this.nestedModalStack.length > 0) { const prevModal = this.nestedModalStack[this.nestedModalStack.length - 1]; prevModal.show(); } } } // 获取表单数据 getFormData(container) { const formData = {}; container.find('input, select, textarea').each(function() { const $el = $(this); const name = $el.attr('name'); if (!name) return; if ($el.attr('type') === 'checkbox') { formData[name] = $el.is(':checked'); } else if ($el.attr('type') === 'radio') { if ($el.is(':checked')) { formData[name] = $el.val(); } } else { formData[name] = $el.val(); } }); return formData; } /** * 设置多个按钮的事件处理 * @param {Object} config - 配置对象 * @param {Function} onAddEntity - 添加实体的回调函数 */ setupMultiButtonHandlers(config, onAddEntity) { const popup = Swal.getPopup(); // 确保弹窗存在 if (!popup) { console.warn('弹窗不存在,无法绑定事件'); return; } // 移除旧的事件监听器(防止重复绑定) this.cleanupMultiButtonHandlers(); // 绑定所有添加按钮事件 this.addEntityButtons = Array.from(popup.querySelectorAll('.add-entity-btn')); this.addEntityButtons.forEach(btn => { const handler = async () => { const targetField = btn.dataset.targetField; const entityType = btn.dataset.entityType; if (onAddEntity) { const newItem = await onAddEntity(entityType, targetField); if (newItem) { this.updateSelectField(popup, targetField, newItem); } } }; btn.addEventListener('click', handler); // 保存处理器以便后续清理 this.buttonHandlers.set(btn, handler); }); } /** * 清理按钮事件处理器 */ cleanupMultiButtonHandlers() { if (this.addEntityButtons) { this.addEntityButtons.forEach(btn => { const handler = this.buttonHandlers.get(btn); if (handler) { btn.removeEventListener('click', handler); this.buttonHandlers.delete(btn); } }); this.addEntityButtons = null; } } /** * 更新下拉框选项 * @param {HTMLElement} popup - 弹窗元素 * @param {string} fieldName - 字段名 * @param {Object} newItem - 新选项 {value, label} */ updateSelectField(popup, fieldName, newItem) { // 确保弹窗仍然存在 if (!popup || !popup.isConnected) { console.warn('弹窗已关闭,无法更新字段'); return; } const select = popup.querySelector(`select[name="${fieldName}"]`); if (select) { // 添加新选项 const option = document.createElement('option'); option.value = newItem.value; option.textContent = newItem.label; option.selected = true; select.appendChild(option); // 如果使用Select2,刷新组件 if ($(select).hasClass('select2-hidden-accessible')) { $(select).trigger('change'); } } } // 安全初始化 Select2 safeInitSelect2($select, options) { try { // 检查是否已初始化 if ($select.data('select2')) { this.safeDestroySelect2($select); } // 设置 dropdownParent 确保在模态框内正确显示 const dropdownParent = options.dropdownParent || Swal.getPopup() || document.body; $select.select2({ ...options, dropdownParent }); $select.addClass('select2-initialized'); return true; } catch (error) { console.error('Select2 initialization failed:', error); return false; } } // 安全销毁 Select2 safeDestroySelect2($select) { try { if ($select.data('select2')) { $select.select2('destroy'); } $select.removeClass('select2-initialized'); return true; } catch (error) { console.error('Select2 destruction failed:', error); return false; } } // 清理所有 Select2 实例 destroyAllSelect2() { const popup = Swal.getPopup(); if (popup) { $(popup).find('.select2-initialized').each((index, element) => { this.safeDestroySelect2($(element)); }); } } } export default SweetalertSystem; SweetalertSystem2.js:472 Uncaught TypeError: Cannot read properties of null (reading ‘querySelectorAll’) at SweetalertSystem.open (SweetalertSystem2.js:472:20) at HTMLButtonElement.showDingdanModal (tianjia3.js:316:55) at HTMLButtonElement.dispatch (jquery-3.2.1.min.js:
07-04
在使用 Vue.js 进行开发时,出现 `TypeError: t.getSourceConfig is not a function` 错误通常与构建工具(如 Webpack)或相关依赖的版本不兼容有关。该错误表明某个模块尝试调用一个不存在的方法 `getSourceConfig`,这可能是由于以下原因导致: 1. **Webpack 配置问题**:某些插件或加载器依赖于特定的 Webpack 方法或配置项,若这些方法在当前 Webpack 版本中已被弃用或移除,则会导致此类错误。 2. **依赖版本不兼容**:Vue.js 项目中使用的某些依赖(如 `vue-loader`、`vue-template-compiler` 等)可能与当前 Webpack 或其他构建工具的版本不兼容[^1]。 3. **第三方插件冲突**:某些第三方插件可能在内部调用了 `getSourceConfig` 方法,而该方法在当前环境下不可用,从而引发错误。 ### 解决方案 #### 1. 检查 Webpack 和相关插件版本 确保 `webpack` 及其相关插件(如 `webpack-cli`、`webpack-dev-server`)版本之间相互兼容。如果使用的是较新版本的 Webpack,某些旧版插件可能无法正常工作。可以尝试降级 Webpack 到稳定版本,并确保所有插件都支持该版本: ```bash npm install webpack@4 webpack-cli@3 --save-dev ``` #### 2. 更新或降级 `vue-loader` 和 `vue-template-compiler` 确保 `vue-loader` 和 `vue-template-compiler` 的版本与 `vue` 保持一致。例如,若使用的是 Vue 2.x,则应安装对应的 `vue-loader@15.x` 和 `vue-template-compiler@2.x`: ```bash npm install vue@2 vue-loader@15 vue-template-compiler@2 --save-dev ``` #### 3. 检查 Babel 和 Loader 配置 确保 `babel-loader` 及其配套依赖(如 `@babel/core`、`@babel/preset-env`)版本兼容。若使用的是较新的 `babel-loader`,可能需要调整其配置或降级到与当前环境兼容的版本: ```bash npm install babel-loader@8 @babel/core @babel/preset-env --save-dev ``` 此外,检查 Webpack 配置文件中是否正确引入了 `VueLoaderPlugin` 和 `vue-loader` 的规则: ```javascript const { VueLoaderPlugin } = require('vue-loader'); module.exports = { // ... module: { rules: [ { test: /\.vue$/, loader: 'vue-loader' }, // 其他规则 ] }, plugins: [ new VueLoaderPlugin(), // 其他插件 ] }; ``` #### 4. 清理缓存并重新安装依赖 有时,Node.js 缓存或 `node_modules` 中残留的旧文件可能导致问题。执行以下命令清理缓存并重新安装依赖: ```bash rm -rf node_modules package-lock.json npm cache clean --force npm install ``` #### 5. 检查第三方插件兼容性 如果项目中使用了第三方插件,尤其是那些与构建流程相关的插件(如 `html-webpack-plugin`、`mini-css-extract-plugin` 等),请确认它们是否与当前 Webpack 版本兼容。如有必要,可尝试更换为更稳定的版本或寻找替代插件。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值