> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aftersell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 结账前要求同意条款

> 一个 Cart SDK 用例：在 Aftersell Cart 中添加条款与条件复选框，并在购物者接受之前阻止结账。

在结账按钮下方添加一个复选框，并在购物者勾选之前阻止其继续。适用于条款确认、年龄门槛以及按订单定制的确认场景。

<Warning>
  \*\*`checkout` 事件无法取消结账。\*\*它是在浏览器跳转前作为通知触发的，因此返回 `false` 或调用 `preventDefault` 都不起作用。控制结账的唯一方法是在按钮被按下*之前*让它不响应点击，本页展示的正是这种做法。

  请将其视为界面层面的阻拦，而非法律保证。有心的购物者仍然可以直接进入结账。
</Warning>

<div id="how-it-works">
  ## 工作原理
</div>

三个部分：

1. 结账按钮下方的一个**自定义代码块**渲染复选框。
2. 在复选框未勾选时，该块通过 [shadow root](/zh/aftersell/cart/sdk-overview#shadowroot) 给购物车的结账按钮和快捷支付按钮添加一个类。
3. **自定义 CSS** 让这个类禁用点击。

<div id="step-1-add-the-checkbox-block">
  ## 第 1 步：添加复选框块
</div>

在你的 Checkout button 块下方添加一个[自定义代码块](/zh/aftersell/cart/custom-code-blocks)，将其切换到 **React component** 模式，然后粘贴：

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  const [accepted, setAccepted] = useState(false);

  useEffect(() => {
    const root = window.aftersell?.cart?.shadowRoot;
    if (!root) return;

    const targets = root.querySelectorAll(
      '.cart-external-checkout-button, .cart-external-express-buttons'
    );
    targets.forEach((el) => el.classList.toggle('checkout-gated', !accepted));
  }, [accepted, props.cart]);

  return (
    <div style={{ width: '100%', fontSize: '14px', textAlign: 'center' }}>
      <label style={{ display: 'flex', gap: '6px', justifyContent: 'center', alignItems: 'center' }}>
        <input
          type="checkbox"
          checked={accepted}
          onChange={(e) => setAccepted(e.target.checked)}
        />
        <span>
          I accept the{' '}
          <a href="https://yourstore.com/terms" target="_blank" rel="noopener noreferrer">
            Terms &amp; Conditions
          </a>
        </span>
      </label>
      {!accepted && (
        <div style={{ color: '#c00', fontWeight: 600, marginTop: '6px' }}>
          Please accept the terms above to continue.
        </div>
      )}
    </div>
  );
}
```

点击 **Compile**，然后开启 **"Use custom template"**。在此之前该块不会渲染任何内容。

`props.cart` 这个依赖项很重要：它会在购物车重新渲染之后重新应用该类，否则类会被抹掉。

<div id="step-2-add-the-css">
  ## 第 2 步：添加 CSS
</div>

在 **Cart settings → Custom CSS** 中：

```css theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
.checkout-gated {
  pointer-events: none !important;
  opacity: 0.5 !important;
}
```

真正阻止点击的是 `pointer-events: none`；透明度只是向购物者展示原因。

<div id="step-3-test-it">
  ## 第 3 步：测试
</div>

在[预览](/zh/aftersell/cart/previewing-carts)中确认：

* 结账按钮在加载时呈灰显状态且不响应点击。
* 勾选复选框后按钮启用；取消勾选后按钮再次禁用。
* 快捷支付按钮同样被限制。
* 在复选框未勾选时，添加或移除商品不会重新启用按钮。

最后一项是最常见的失败点。如果按钮在购物车变化后自行重新启用，说明 effect 没有重新运行。检查 `props.cart` 是否在依赖数组中。

<div id="tracking-who-accepted">
  ## 记录谁接受了条款
</div>

复选框只是浏览器端的状态；它永远不会进入订单。要记录接受情况，可在加购时将其作为属性写到每个行项目上：

```html theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
<input type="hidden" name="properties[_terms_version]" value="2026-01">
```

将它添加到主题中的产品表单里。Shopify 会直接从表单读取 `properties[...]`，所以无论由谁执行添加——Aftersell、主题或其他应用——该值都会到达订单。

以 `_` 为前缀的属性不会出现在面向买家的行项目中，但仍会传到 Shopify，因此会出现在订单上。这记录的是当时生效的条款*版本*，而不是购物者勾选了复选框这一事实。

<div id="things-to-get-right">
  ## 需要注意的要点
</div>

* **只针对 `cart-external-*` 类。** `cart-internal-*` 这些对应的类是购物车自身的内部结构，不是给你的代码用的抓手。参见[自定义 CSS](/zh/aftersell/cart/custom-css)。
* \*\*使用 `shadowRoot` 前先检查它是否存在。\*\*在购物车启动之前它是 `undefined`。
* **在购物车加载完成之前该块不渲染任何内容**，因此结账按钮绝不会在限制生效前出现短暂可用的情况。
* **抛出异常的 React 块什么也不渲染**，而购物车的其余部分照常运行，在这里就意味着结账按钮失去保护。发布前请在预览中测试。

<div id="where-to-go-next">
  ## 后续阅读
</div>

* **[自定义代码块](/zh/aftersell/cart/custom-code-blocks)**：React 模式及其 props。
* **[自定义 CSS](/zh/aftersell/cart/custom-css)**：公开类的命名约定。
* **[Events](/zh/aftersell/cart/sdk-events#checkout)**：`checkout` 事件能做什么、不能做什么。
