You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Polymer/Vaadin14集成Braintree支付网关#id选择器失效问题

问题描述

我正尝试在基于Polymer开发的Vaadin 14前端中集成Braintree支付网关,通过自定义Vaadin前端视图加载https://js.braintreegateway.com/web/dropin/1.9.4/js/dropin.min.js脚本后,调用dropin.create方法,代码如下:

import{PolymerElement}from'@polymer/polymer/polymer-element.js';
import'@polymer/iron-icon/iron-icon.js';
import{html}from'@polymer/polymer/lib/utils/html-tag.js';
import '@webcomponents/webcomponentsjs/webcomponents-loader.js';
import'@polymer/polymer/polymer-legacy.js';
import'@polymer/iron-flex-layout/iron-flex-layout.js';


import{mixinBehaviors}from'@polymer/polymer/lib/legacy/class.js';
import{Polymer}from'@polymer/polymer/lib/legacy/polymer-fn.js';
import{setTouchAction}from'@polymer/polymer/lib/utils/gestures.js';
import{afterNextRender}from'@polymer/polymer/lib/utils/render-status.js';
import'@vaadin/vaadin-text-field/vaadin-text-field.js';

import { sharedStyles } from './drop-in.js';

let dropin = require('braintree-web-drop-in');

class BrainTreeVaadin extends PolymerElement {

    <vaadin-vertical-layout class="main-div-layout-boder padding5">
        <form id="paymentForm" method="post" action="/checkout" class="main-screen-vert-layout-row">
            <div id="containPayment" class="main-screen-vert-layout-row">
                <div id="btDropin" class="main-screen-vert-layout-row"></div>
            </div>
            <vaadin-text-field id="nonce" value={{valueNonce}} hidden></vaadin-text-field>
            <vaadin-button id="butPayment" theme="theme-button-02" class="button-row">Payment</vaadin-button>
        </form>
    </vaadin-vertical-layout>

createFormPayment(){

let form = this.$.paymentForm;
let butPayment = this.$.butPayment;
let btDropin =  this.$.btDropin;
let textNonce = this.$.nonce;

dropin.create({
  authorization: this.clientToken,
  container: btDropin,
  card: {
    cardholderName: {
        required: true
    }
  },
  paypal: {
     flow: 'vault',
     currency: 'USD'
  },
  paypalCredit: {
     flow: 'vault',
     currency: 'USD'
  }
}
}
}

运行后出现报错,经排查问题出在dropin.min.js内部加载的https://www.paypalobjects.com/api/checkout.min.js使用#id格式的JS选择器无法获取到对应HTML元素。
Braintree标准实现中,braintree.dropin.create方法的container参数支持传入#element_id格式的选择器,官方示例代码如下:

<div class="bt-drop-in-wrapper">
    <div id="bt-dropin"></div>
 </div>

<div th:include="fragments/homefooter :: footer"></div>
        <script src="https://js.braintreegateway.com/web/dropin/1.9.4/js/dropin.min.js"></script>
        <script th:inline="javascript">
            /*<![CDATA[*/
            var form = document.querySelector('#payment-form');
            var client_token = [[${clientToken}]];
        
            braintree.dropin.create({
              authorization: client_token,
              container: '#bt-dropin',
              paypal: {
                flow: 'vault'
              }
            }, function (createErr, instance) {
              form.addEventListener('submit', function (event) {
                  event.preventDefault();
                  $('#errorDiv').hide();
                  $('#serverSideErrorDiv').hide();
                  
                  instance.requestPaymentMethod(function (err, payload) {
                    if (err) {
                      console.log('Error', err);
                      showError(err);
                      return;
                    }
            
                    // Add the nonce to the form and submit
                    document.querySelector('#nonce').value = payload.nonce;
                    form.submit();
                  });
              });
            });

用户最初疑问为如何让Vaadin视图支持#element_id格式的JS元素选择器,后续两次更新排查确认:

  • 该问题不属于Vaadin Flow范畴,属于Polymer相关问题
  • 最终定位为Braintree侧兼容问题,与Polymer无关
解决方案

问题本质是旧版Braintree/PayPal SDK仅支持在全局document DOM树中查询元素,而Polymer自定义元素默认使用Shadow DOM隔离内部DOM,全局document.querySelector无法穿透Shadow DOM获取内部元素,导致选择器失效。可通过以下任意方案解决:

  1. 关闭自定义元素的Shadow DOM
    在Polymer元素类中添加createRenderRoot方法,关闭Shadow DOM,让元素内部DOM直接挂载到全局DOM树,全局ID选择器即可正常访问内部元素:
class BrainTreeVaadin extends PolymerElement {
  // 关闭Shadow DOM
  createRenderRoot() {
    return this;
  }
  // 其余原有代码保持不变
}
  1. 升级Braintree Drop-in SDK版本
    1.38.0及以上版本的Braintree Drop-in SDK已优化元素查询逻辑,兼容Shadow DOM场景,升级SDK版本后无需修改现有业务代码即可正常运行。
  2. 将Braintree渲染容器移至全局DOM
    若无法升级SDK也不想关闭Shadow DOM,可在全局DOM中创建独立的容器元素,将Braintree组件渲染到该全局容器中,再通过绝对定位或者slot的方式将容器嵌入到Vaadin视图的对应位置即可。

内容的提问来源于stack exchange,提问作者Thang Le

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 06:21:03