【问题标题】:How can I style a Stripe Elements input with Bootstrap?如何使用 Bootstrap 设置 Stripe Elements 输入的样式?
【发布时间】:2018-02-12 19:48:34
【问题描述】:

我正在构建一个使用 Stripe 处理付款的简单网站。我正在使用 Bootstrap 进行样式设置。当我使用 Stripe Elements 插入付款字段时,它们没有使用 Bootstrap 进行样式设置。如何将 Bootstrap 的样式应用于 Elements 支付字段?

【问题讨论】:

    标签: twitter-bootstrap stripe-payments stripe.js


    【解决方案1】:

    好的,所以我必须弄清楚这一点,因为我使用的是 Stripe.js v2,并且 Stripe 技术支持向我解释了安全漏洞,所以我觉得有义务切换到 Stripe.js v3 “Elements”。他们所说的是,与您的信用卡表单元素在同一页面上的任何 javascript 都可以获取敏感信用卡数据的值。我想如果一个人正在拉入外部脚本,这可能会发生......我想它一定已经发生了,否则他们不会关心它。无论如何,这就是我如何让我的 Stripe.js v3 元素与 Bootstrap 4 输入组一起工作。这是一个完整的工作示例,您只需要更改公钥。

    默认的基于 jQuery 的示例

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <title>Stripe.js v3 with Bootstrap 4 Test</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
        <style>
            /* Blue outline on focus */
            .StripeElement--focus {
                border-color: #80BDFF;
                outline:0;
                box-shadow: 0 0 0 .2rem rgba(0,123,255,.25);
                transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
            }
            /* Can't see what I type without this */
            #card-number.form-control,
            #card-cvc.form-control,
            #card-exp.form-control {
                display:inline-block;
            }
        </style>
    </head>
    <body>
    
        <div class="container-fluid">
            <h1 class="mt-5">Stripe.js v3 with Bootstrap 4 (beta) Test</h1>
            <div id="card-errors" role="alert"></div>
            <div class="card">
                <div class="card-body">
                    <form id="payment-form">
                        <label for="name">Name on Card</label>
                        <div class="input-group mb-2">
                            <div class="input-group-prepend">
                                <span class="input-group-text">A</span>
                            </div>
                            <input type="text" class="form-control" id="name">
                            <div class="input-group-append">
                                <span class="input-group-text">B</span>
                            </div>
                        </div>
                        <label for="card-number">Credit Card Number</label>
                        <div class="input-group mb-2">
                            <div class="input-group-prepend">
                                <span class="input-group-text">C</span>
                            </div>
                            <span id="card-number" class="form-control">
                                <!-- Stripe Card Element -->
                            </span>
                            <div class="input-group-append">
                                <span class="input-group-text">D</span>
                            </div>
                        </div>
                        <label for="card-cvc">CVC Number</label>
                        <div class="input-group mb-2">
                            <div class="input-group-prepend">
                                <span class="input-group-text">E</span>
                            </div>
                            <span id="card-cvc" class="form-control">
                                <!-- Stripe CVC Element -->
                            </span>
                        </div>
                        <label for="card-exp">Expiration</label>
                        <div class="input-group mb-2">
                            <span id="card-exp" class="form-control">
                                <!-- Stripe Card Expiry Element -->
                            </span>
                            <div class="input-group-append">
                                <span class="input-group-text">F</span>
                            </div>
                        </div>
                        <button id="payment-submit" class="btn btn-primary mt-1">Submit Payment</button>
                    </form>
                </div>
            </div>
        </div>
    
    <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
    <script src="https://js.stripe.com/v3/"></script>
    <script>
        $(document).ready(function(){
    
            // Create a Stripe client
            var stripe = Stripe('pk_test_XxXxXxXxXxXxXxXxXxXxXxXx');
    
            // Create an instance of Elements
            var elements = stripe.elements();
    
            // Try to match bootstrap 4 styling
            var style = {
                base: {
                    'lineHeight': '1.35',
                    'fontSize': '1.11rem',
                    'color': '#495057',
                    'fontFamily': 'apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'
                }
            };
    
            // Card number
            var card = elements.create('cardNumber', {
                'placeholder': '',
                'style': style
            });
            card.mount('#card-number');
    
            // CVC
            var cvc = elements.create('cardCvc', {
                'placeholder': '',
                'style': style
            });
            cvc.mount('#card-cvc');
    
            // Card expiry
            var exp = elements.create('cardExpiry', {
                'placeholder': '',
                'style': style
            });
            exp.mount('#card-exp');
    
            // Submit
            $('#payment-submit').on('click', function(e){
                e.preventDefault();
                var cardData = {
                    'name': $('#name').val()
                };
                stripe.createToken(card, cardData).then(function(result) {
                    console.log(result);
                    if(result.error && result.error.message){
                        alert(result.error.message);
                    }else{
                        alert(result.token.id);
                    }
                });
            });
    
        });
    </script>
    </body>
    </html>
    

    我仅在 Firefox、Chrome 和 Android 上的 Chrome 中进行了测试。似乎工作正常。如果您遇到任何问题,请告诉我。

    可选的基于 Vue.js 的示例

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <title>Stripe.js v3 with Bootstrap 4 and Vue.js</title>
        <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css"/>
        <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css"/>
        <style>
            /* This background color not essential for the example */
            html, body {
                background:#999;
            }
    
            /* Padding for Stripe Element containers */
            .stripe-element-container {
                padding-top: .55rem;
                padding-bottom: .50rem;
            }
    
            /* Blue outline on focus */
            .StripeElement--focus {
                border-color: #80BDFF;
                outline:0;
                box-shadow: 0 0 0 .2rem rgba(0,123,255,.25);
                transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
            }
    
            /* Can't see what I type without this */
            #card-number.form-control,
            #card-cvc.form-control,
            #card-exp.form-control {
                display:inline-block;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <stripe-form inline-template>
                <div class="container-fluid">
                    <div class="row">
                        <div class="col-md-4 offset-md-4 pt-5">
                            <div class="card">
                                <div class="card-header">
                                    <h3 class="mb-0">Pay Now</h3>
                                </div>
                                <div class="card-body">
                                    <div v-bind:class="{alert: activeError, 'alert-danger': activeError}" role="alert" v-html="errorText"></div>
    
                                    <form>
    
                                        <div class="form-group mb-4">
                                            <label for="name">Name on Card</label>
                                            <input type="text" class="form-control" v-model="ccName" />
                                        </div>
    
                                        <div class="form-group">
                                            <label for="card-number">Credit Card Number</label>
                                            <span id="card-number" class="form-control stripe-element-container">
                                                <!-- Stripe Card Element -->
                                            </span>
                                        </div>
    
                                        <div class="form-group">
                                            <label for="card-cvc">CVC Number</label>
                                            <span id="card-cvc" class="form-control stripe-element-container">
                                                <!-- Stripe CVC Element -->
                                            </span>
                                        </div>
    
                                        <div class="form-group">
                                            <label for="card-exp">Expiration</label>
                                            <span id="card-exp" class="form-control stripe-element-container">
                                                <!-- Stripe Card Expiry Element -->
                                            </span>
                                        </div>
    
                                        <button @click.prevent="paymentSubmit" class="btn btn-primary mt-1 float-right">Submit Payment</button>
    
                                    </form>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </stripe-form>
            <modal></modal>
        </div>
    
    <script src="https://unpkg.com/vue@2.5.13/dist/vue.js"></script>
    <script src="https://unpkg.com/babel-polyfill@latest/dist/polyfill.min.js"></script>
    <script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.js"></script>
    <script src="https://js.stripe.com/v3/"></script>
    <script>
    
    // Your Stripe public key
    const stripePublicKey = 'pk_test_XxXxXxXxXxXxXxXxXxXxXxXx';
    
    /**
     * Class allows firing of events and 
     * listening of events between components
     */
    window.Events = new class {
    
        constructor(){
            this.vue = new Vue();
        }
    
        fire( event, data = null ){
            this.vue.$emit( event, data );
        }
    
        listenFor( event, callback ){
            this.vue.$on( event, callback );
        }
    }
    
    /**
     * See: https://bootstrap-vue.js.org/docs/components/modal/
     */
    Vue.component('modal', {
    
        template: `
            <div>
                <b-modal ref="myModalRef" ok-only ok-title="Close" v-bind:title="title">
                    <p class="mb-0">{{ body }}</p>
                </b-modal>
            </div>
        `,
    
        data: function(){
            return {
                title: '',
                body: ''
            }
        },
    
        methods: {
            showModal () {
              this.$refs.myModalRef.show()
            }
            /* This not needed for this example
            ,
            hideModal () {
              this.$refs.myModalRef.hide()
            }
            */
        },
    
        created(){
            Events.listenFor('modalShow', ( data ) => {
                this.title = data.title;
                this.body = data.message;
                this.showModal();
            });
        }
    
    });
    
    Vue.component('stripe-form', {
    
        data: function(){
            return { 
                activeError: false,
                errorText: '',
                ccName: '',
                stripe: null,
                card: null,
                cvc: null,
                exp: null
            }
        },
    
        methods: {
            paymentSubmit: function(){
                let cardData = {
                    'name': this.ccName
                };
                // Ensure the name field is not empty
                if( cardData.name.trim() == '' ){
                    // Show an error
                    this.activeError = true;
                    this.errorText = '<b>Submission Error:</b><br />Name is required.';
                    // Abort !!
                    return;
                }
                this.stripe.createToken( this.card, cardData).then( (result) => {
                    if(result.error && result.error.message){
    
                        // Show any errors
                        this.activeError = true;
                        this.errorText = '<b>Submission Error:</b><br />' + result.error.message;
    
                    }else{
    
                        /**
                         * Success message in modal.
                         * This is normally where you'd post to your server, 
                         * and have it actually attempt the credit card transaction
                         * using the token ID that was just received.
                         */
                        Events.fire('modalShow', {
                            'title': 'Success',
                            'message': result.token.id
                        });
    
                        // Clear the form
                        this.activeError = false;
                        this.errorText = '';
                        this.ccName = '';
                        // Stripe elements must be cleared in a special way
                        this.card.clear();
                        this.cvc.clear();
                        this.exp.clear();
                    }
                });
            }
        },
    
        mounted: function(){
            // Create a Stripe client
            this.stripe = Stripe( stripePublicKey );
    
            // Create an instance of Elements
            const elements = this.stripe.elements();
    
            /**
             * Try to match bootstrap 4 styling.
             * --------------------------------
             * fontSize was in rem units, but Stripe says that it should be in pixels.
             */
            const style = {
                base: {
                    'fontSize': '16px',
                    'color': '#495057',
                    'fontFamily': 'apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'
                }
            };
    
            // Card number
            this.card = elements.create('cardNumber', {
                'placeholder': '',
                'style': style
            });
            this.card.mount('#card-number');
    
            // CVC
            this.cvc = elements.create('cardCvc', {
                'placeholder': '',
                'style': style
            });
            this.cvc.mount('#card-cvc');
    
            // Card expiry
            this.exp = elements.create('cardExpiry', {
                'placeholder': '',
                'style': style
            });
            this.exp.mount('#card-exp');
        }
    
    });
    
    new Vue({ el: '#app' });
    
    </script>
    </body>
    </html>
    

    这个 Vue.js 示例可以从一些工作中受益,但可能会帮助您入门。

    【讨论】:

    • 这对我来说看起来很棒!你肯定抓住了一些我错过的风格。
    • 非常感谢!为我工作!
    • 这很好,我将如何改变错误的样式?
    • 这是一个简单的 Codelply 我创建的 codeply.com/p/PPX9p3vKEL
    【解决方案2】:

    在深入研究文档后,我发现 https://stripe.com/docs/stripe.js#the-element-container 说“你 应该为您安装元素的容器设置样式,就好像它是 在您的页面上。”

    通过将 Bootstrap 的 form-control 类添加到我正在安装元素的 &lt;div&gt; 中,该字段看起来几乎与任何其他 Bootstrap 样式的输入字段一样:

    <div id="card-element" class="form-control"></div>
    

    由于某种原因,场地的高度不太匹配,但经过反复试验,我明白了 与:

    var stripe = Stripe('your_key');
    var elements = stripe.elements();
    var card = elements.create('card', { style:
      {
        base: {
          lineHeight: '1.429'
        }
      }
    });
    card.mount('#card-element');
    

    【讨论】:

    • 这是对的,但你还需要在元素获得焦点时应用边框颜色。此外,如果您正在使用 Bootstrap 4 beta 并尝试使用输入组,那么您必须更改元素 CSS 以使其为 display:block 而不是 display:flex。我有一个工作演示......但这并不是你问题的真正答案......除非它是。
    • 好点!这听起来确实像答案:) 我很想看演示。
    • 就我而言,form-control 正在以某种方式被删除。
    • 很简单。谢谢。
    • 我尝试了这个,并从 stripe 收到一条消息,说不建议更改 lineHeight,因为报告的各种浏览器上的视觉不一致。它建议填充元素容器。
    【解决方案3】:

    这就是我们使用

    所需的全部内容
      <div class="form-group">
        <label for="card-element">Credit or debit card</label>
        <div id="card-element" class="form-control" style='height: 2.4em; padding-top: .7em;'>
          <!-- A Stripe Element will be inserted here. -->
        </div>
      </div>
    

    【讨论】:

    • 非常简单。
    • javascript 是什么样的?
    • 你只能通过内联css对特定区域进行样式化,其余的需要通过JS来完成。
    【解决方案4】:

    添加另一个答案,因为我觉得这里最简单的答案有点不完整。添加了错误显示和用于将令牌发送到后端的 JavaScript,以防您想这样做。

    这个 HTML(来自他们的默认文档,添加了 Bootstrap 4 元素)

    <form action="/charge" method="post" id="payment-form">
      <div class="form-group">
        <label for="card-element">
            Credit or debit card
        </label>
        <div id="card-element" class="form-control">
            <!-- A Stripe Element will be inserted here. -->
        </div>
    
        <!-- Used to display Element errors. -->
        <div id="card-errors" role="alert"></div>
      </div>
    
      <button>Submit Payment</button>
    </form>
    

    这是 JavaScript(同样来自他们的默认文档,但我在这里使用 jQuery,但您不必这样做)

    <script src="https://js.stripe.com/v3/"></script>
    <script>
    (function ($) {
        // Set your publishable key: remember to change this to your live publishable key in production
        // See your keys here: https://dashboard.stripe.com/account/apikeys
        var stripe = Stripe('yourPublishableKeyHere');
        var elements = stripe.elements();
    
        // Custom styling can be passed to options when creating an Element.
        var style = {
          base: {
            // Add your base input styles here. For example:
            fontSize: '16px',
            color: '#32325d',
          },
        };
    
        // Create an instance of the card Element.
        var card = elements.create('card', {style: style});
    
        // Add an instance of the card Element into the `card-element` <div>.
        card.mount('#card-element');
    
    
        // Create a token or display an error when the form is submitted.
        var form = document.getElementById('payment-form');
        form.addEventListener('submit', function(event) {
          event.preventDefault();
    
          stripe.createToken(card).then(function(result) {
            if (result.error) {
              // Inform the customer that there was an error.
              var errorElement = document.getElementById('card-errors');
              errorElement.textContent = result.error.message;
            } else {
              // Send the token to your server.
              stripeTokenHandler(result.token);
            }
          });
        });
    
        function stripeTokenHandler(token) {
          // Insert the token ID into the form so it gets submitted to the server
          var form = document.getElementById('payment-form');
          var hiddenInput = document.createElement('input');
          hiddenInput.setAttribute('type', 'hidden');
          hiddenInput.setAttribute('name', 'stripeToken');
          hiddenInput.setAttribute('value', token.id);
          form.appendChild(hiddenInput);
    
          // Submit the form
          form.submit();
        }
    })(jQuery);
    </script>
    

    【讨论】:

    • 非常感谢。这个例子让我的生活变得轻松多了!
    【解决方案5】:

    改进其他答案,我得到了以下解决方案。不过,带上一粒盐。 .StripeElement--focus.card-element-disabled 的 CSS 是从 Bootstrap 复制的,因此您可能希望从您正在使用的版本中获取它们(我想我有 4.4)。

    另外,我没有复制支付逻辑,因为它特定于我的应用程序,但是当按下按钮并且 JavaScript 开始处理内容时我调用 disable_form,当 JavaScript 完成并且表单可以是 enable_form重新启用(可能是因为出现错误,否则你只是转到另一个页面)。

    <style>
      .StripeElement--focus {
          color: #495057;
          background-color: #fff;
          border-color: #80bdff;
          outline: 0;
          box-shadow: 0 0 0 .2rem rgba(0,123,255,.25);
      }
      .card-element-disabled {
          background-color: #e9ecef;
          opacity: 1;
      }
      #card-element {
          display: flex;
          align-items: center;
      }
      #card-element div {
          flex-grow: 1;
      }
      #card-element-error {
          color: #ff0000;
      }
    </style>
    <script>
      function disable_form() {
          $(".form-control").prop('disabled', true);
          card.update({disabled: true});
          $("#submit-btn").prop('disabled', true).html("Loading");
          $("#card-element").addClass('card-element-disabled');
      }
    
      function enable_form() {
          $(".form-control").prop('disabled', false);
          card.update({disabled: false});
          $("#submit-btn").prop('disabled', false).html("Submit");
          $("#card-element").removeClass('card-element-disabled');
      }
    
      var stripe = Stripe('{{ stripe_publishable_key }}');
      var elements = stripe.elements();
      var card = elements.create('card');
    
      function setup_stripe() {
          card.mount('#card-element');
      }
    
      setTimeout(setup_stripe, 0);
    </script>
    
    <form id="payment-form">
        <!-- all other fields -->
    
        <div class="form-group">
          <label for="card-element">Card number</label>
          <div id="card-element" class="form-control"></div>
        </div>
    
        <div id="card-element-error" role="alert"></div>
        <button type="submit" class="btn btn-primary" id="submit-btn">Submit</button>
    </form>
    

    【讨论】:

      【解决方案6】:

      我正在使用带有 react 的条带,并且我试图在父容器上使用类,但它对我不起作用。所以,我最终为容器使用了内联样式。 这是对我有用的最终代码。

      const containerStyles = {
      border: '1px solid #d3d3d3',
      padding: '5px 10px 5px 10px',
      borderRadius: '4px',
      width: '100%', };
      
      const cardNumberElementOptions = {
      style: {
        base: {
          fontSize: '14px',
          lineHeight: '45px',
        },
      },
      placeholder: 'Card Number',
      };
      
      <div style={containerStyles}>
            <CardNumberElement options={cardNumberElementOptions} />
      </div>
      

      【讨论】:

        猜你喜欢
        • 2017-10-13
        • 2021-04-24
        • 2022-01-22
        • 2016-04-28
        • 2021-10-13
        • 2018-09-22
        • 1970-01-01
        • 2012-02-16
        • 1970-01-01
        相关资源
        最近更新 更多