magento2 checkout页面对shipping address指定字段添加自定义验证
magento2 checkout页面对shipping address指定字段添加自定义验证
接到客户需求,想要在用户输入street字段的时候,输入内容若包含P.O. BOX 则有相关提示:

首先想到的肯定是添加blur或者keyup事件进行输入监听,这样的话要不了几分钟就搞定了。
若遵循magento开发规范,则需要另外想法子,项目用了onestepcheckout插件,但是原理都是一样的,在主题或者自定义的module里面重写就行了。
首先用户点击place order的时候验证:
checkout_index_index:找到并且替换对应内容
- uiComponent
- Aheadworks_OneStepCheckout/js/view/payment-method/email-validator
- Aheadworks_OneStepCheckout/js/view/checkout-agreements/validation
- Aheadworks_OneStepCheckout/js/view/streetValidator
streetValidator注册验证器器内容:
/** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define( [ 'uiComponent', 'Magento_Checkout/js/model/payment/additional-validators', 'Aheadworks_OneStepCheckout/js/model/streetValidator' ], function (Component, additionalValidators, streetValidator) { 'use strict'; additionalValidators.registerValidator(streetValidator); return Component.extend({}); } );
Aheadworks_OneStepCheckout/js/model/streetValidator.js文件内容:
define( [ 'jquery', 'Magento_Ui/js/model/messageList', 'Magento_Checkout/js/model/quote' ], function ($,messageList,quote) { 'use strict'; return { /** * Validate street not have po box * * @returns {boolean} */ validate: function() { var pass = false; //在这里添加自己的一些验证代码 //验证不通过返回错误信息 messageList.addErrorMessage({message: 'show message!' }); return pass; } } );
验证不通过的效果:

添加street内容更改时触发事件,借鉴postcode验证方式:
Magento_Checkout/js/model/shipping-rates-validator.js
/** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define([ 'jquery', 'ko', 'Magento_Checkout/js/model/shipping-rates-validation-rules', 'Magento_Checkout/js/model/address-converter', 'Magento_Checkout/js/action/select-shipping-address', 'Magento_Checkout/js/model/postcode-validator', 'Magento_Checkout/js/model/default-validator', 'mage/translate', 'uiRegistry', 'Magento_Checkout/js/model/shipping-address/form-popup-state', 'Magento_Checkout/js/model/quote' ], function ( $, ko, shippingRatesValidationRules, addressConverter, selectShippingAddress, postcodeValidator, defaultValidator, $t, uiRegistry, formPopUpState ) { 'use strict'; var checkoutConfig = window.checkoutConfig, validators = [], observedElements = [], postcodeElement = null, postcodeElementName = 'postcode', streetElementName = 'street.0',//定义验证字段元素名称 streetElementFormName = 'street[0]', streetElement = null; validators.push(defaultValidator); return { validateAddressTimeout: 0, validateDelay: 2000, /**这个方法会注册各个shipping method插件的验证器,比如ups,free shipping tablerate等 * @param {String} carrier * @param {Object} validator */ registerValidator: function (carrier, validator) { //checkoutConfig里面保存了很多配置信息,这里取的是已经开启的shipping method的名称; if (checkoutConfig.activeCarriers.indexOf(carrier) !== -1) { //注册shipping method提供的验证器,前提是该shipping method已经开启; validators.push(validator); } }, /**验证数据 * @param {Object} address * @return {Boolean} */ validateAddressData: function (address) { return validators.some(function (validator) { return validator.validate(address); }); }, /** * 初始化字段,对应字段绑定事件 * * @param {String} formPath */ initFields: function (formPath) { var self = this, //elements通过shippingRatesValidationRules里面获取各个shipping method提供的rules返回的字段,我这里因为跟shipping method无关就直接把street插入进去了。 elements = shippingRatesValidationRules.getObservableFields(); if ($.inArray(postcodeElementName, elements) === -1) { // Add postcode field to observables if not exist for zip code validation support elements.push(postcodeElementName); } //在这里添加street字段 if ($.inArray(streetElementName, elements) === -1) { // Add street field to observables if not exist elements.push(streetElementName); } $.each(elements, function (index, field) { uiRegistry.async(formPath + '.' + field)(self.doElementBinding.bind(self)); }); }, /** * 将请求绑定到表单元素 * * @param {Object} element * @param {Boolean} force * @param {Number} delay */ doElementBinding: function (element, force, delay) { var observableFields = shippingRatesValidationRules.getObservableFields(); if (element && (observableFields.indexOf(element.index) !== -1 || force)) { if (element.index !== postcodeElementName) { this.bindHandler(element, delay); } //这里因为street是数组格式,index=0 所以我换了inputName方式判断,模拟postcode的处理方式 if (element.inputName !== streetElementFormName) { this.bindHandler(element, delay); } } if (element.index === postcodeElementName) { this.bindHandler(element, delay); postcodeElement = element; } if (element.inputName === streetElementFormName) { this.bindHandler(element, delay); streetElement = element; } }, /** * @param {*} elements * @param {Boolean} force * @param {Number} delay */ bindChangeHandlers: function (elements, force, delay) { var self = this; $.each(elements, function (index, elem) { self.doElementBinding(elem, force, delay); }); }, /** * @param {Object} element * @param {Number} delay */ bindHandler: function (element, delay) { var self = this; delay = typeof delay === 'undefined' ? self.validateDelay : delay; if (element.component.indexOf('/group') !== -1) { $.each(element.elems(), function (index, elem) { self.bindHandler(elem); }); } else { element.on('value', function () { if (!formPopUpState.isVisible()) { clearTimeout(self.validateAddressTimeout); self.validateAddressTimeout = setTimeout(function () { self.postcodeValidation(); self.validateFields(); self.streetValidation();//模拟postcode验证,添加了自己的验证方法 }, delay); } }); observedElements.push(element); } }, streetValidation: function (){ streetElement.error(null); //添加自定义验证内容 if(!pass){ streetElement.error('PLEASE NOTE: WE DO NOT SHIP TO P.O. BOXES!'); } return pass; }, /** * @return {*} */ postcodeValidation: function () { var countryId = $('select[name="country_id"]').val(), validationResult, warnMessage; if (postcodeElement == null || postcodeElement.value() == null) { return true; } postcodeElement.warn(null); validationResult = postcodeValidator.validate(postcodeElement.value(), countryId); if (!validationResult) { warnMessage = $t('Provided Zip/Postal Code seems to be invalid.'); if (postcodeValidator.validatedPostCodeExample.length) { warnMessage += $t(' Example: ') + postcodeValidator.validatedPostCodeExample.join('; ') + '. '; } warnMessage += $t('If you believe it is the right one you can ignore this notice.'); postcodeElement.warn(warnMessage); } return validationResult; }, /** * Convert form data to quote address and validate fields for shipping rates */ validateFields: function () { var addressFlat = addressConverter.formDataProviderToFlatData( this.collectObservedData(), 'shippingAddress' ), address; if (this.validateAddressData(addressFlat)) { addressFlat = uiRegistry.get('checkoutProvider').shippingAddress; address = addressConverter.formAddressDataToQuoteAddress(addressFlat); selectShippingAddress(address); } }, /** * Collect observed fields data to object * * @returns {*} */ collectObservedData: function () { var observedValues = {}; $.each(observedElements, function (index, field) { observedValues[field.dataScope] = field.value(); }); return observedValues; } }; });
内容更改就会触发验证:
最后:一定要注意位置和命名,遇到问题浏览器断点调试,熟悉处理流程以及对应数据变化,这里可能不是最好的和最规范的操作。如果有更好的方法,希望指出来改进改进。
