Svelte 应用程序错误:global.css 覆盖组件级别 CSS

Svelte application bug: global.css overwrites component-level CSS

在 Svelte 应用程序中,我有一个简单验证的表单。

形式

<form id="surveyForm" class="mt-4">
    <div class="form-group">
      <input type="text" class="form-control" placeholder="First name">
    </div>
    <div class="form-group">
      <input type="text" class="form-control" placeholder="Last name">
    </div>
    <button class="btn btn-full" on:click={Continue}>Continue</button>
</form>

验证:

import {fly, fade} from 'svelte/transition';
let hasError = false;
let errMessage = "";
let isSuccessVisible = false;

function validateInput() {
    var surveyForm = document.getElementById('surveyForm'),
        inputFields = surveyForm.querySelectorAll('input[type=text]');

    hasError = false;

    inputFields.forEach(function(field) {
        field.classList.remove("is-invalid");
        var inputFieldVal = field.value;
        if (inputFieldVal.length == 0) {
            field.classList.add("is-invalid");
            hasError = true;
        }
    });
    errMessage = "All the fileds are mandatory";
}


function Continue(e) {
    e.preventDefault();
    validateInput();
    if (hasError == false) {
        isSuccessVisible = true;

        setTimeout(function() {
            isSuccessVisible = false;
        }, 3000);
    }
}

为了给无效的表单字段一个红色边框,我使用border: 1px solid #c00 !important:

.error-alert {
    border: 1px solid #c00 !important;
    color: #c00;
}

class is-invalid 已正确添加(和删除),但默认 global.css 样式 覆盖我的组件级样式 ,正如您在 REPL.

中看到的

为什么会这样?什么是可靠的修复?


注意:所描述的案例是一个简化的案例,实际上我可能需要其他验证,比如确保该值是数字。我必须实施的解决方案不是非常具体

在 REPL 中,您会看到以下警告:

Unused CSS selector (87:1)

那是因为 .is-invalid 选择器未在标记中的任何位置使用 — 如果 classname 未使用,Svelte 会告诉您并删除它。为了让 Svelte 能够 'see' 它,它必须在标记中——你不能用 classList 以编程方式添加它。 (这是一项功能,而不是错误:以编程方式操作 DOM 将不可避免地导致您的视图与您的状态不同步。)

虽然在这种情况下,您不需要向输入元素添加 class,也不需要在函数内部进行检查。您可以只使用输入的 required 属性和 :invalid CSS 选择器:

<input type="text" class="form-control" placeholder="First name" required>
input:invalid {
  border: 1px solid #c00;
}

:invalid 状态将在用户提交任何数据之前应用,因此您可能需要添加一个 class 来指示用户是否已尝试提交:

<form id="surveyForm" class="mt-4" class:submitted>
  <div class="form-group">
    <input type="text" class="form-control" placeholder="First name" required>
  </div>

  <!-- ... -->
</form>
.submitted input:invalid {
  border: 1px solid #c00;
}

添加 class 的最简单方法是在按钮上的 click 事件处理程序中。

Here's a demo.

使用您在 HTML 中免费获得的东西还有其他好处。例如,只要存在验证错误,表单就不会提交(并且验证不限于 'required' — 您可以指定特定模式,或使用例如 type="email" 来要求有效的电子邮件地址等),这意味着在您的 submit 事件处理程序中,您已经知道输入是有效的。

您可以通过使用 HTML5 客户端表单验证来使用 Rich 描述的用于其他验证的技术。可以在 MDN

上找到更多信息
<form id="surveyForm" class="mt-4" class:submitted>
    <div class="form-group">
    <input type="text" class="form-control" placeholder="First name" required>
  </div>
    <div class="form-group">
    <input type="text" class="form-control" placeholder="Last name" required>
  </div>
    <div class="form-group">
    <input type="number" class="form-control" placeholder="Enter a number" required>
  </div>
    <div class="form-group">
    <input type="email" class="form-control" placeholder="Email" required>
  </div>
    <div class="form-group">
    <input type="date" class="form-control" placeholder="Date" required>
  </div>
  <button class="btn btn-full" on:click|preventDefault={Continue}>Continue</button>
</form>

REPL

如果您不想使用它 - 或者由于某种原因它没有涵盖您的所有用例 - 您可以使用 Svelte 操作 类 而不是直接访问 DOM :

<div class="form-group">
    <input bind:value={second} type="text" class="form-control" class:is-invalid="{ submitted && second.length == 0 }" placeholder="Last name">
</div>

REPL

Svelte 删除您的 .is-invalid 样式的原因是因为 Svelte 不使用它。在这种情况下我不推荐它,但您可以强制 Svelte 使用 :global():

保持样式
:global(.is-invalid) {
    border: 1px solid #c00;
}

REPL