ASP.NET Core 8 MVC 中输入错误状态的自定义 TailwindCSS 样式

问题描述 投票:0回答:1

我正在开发一个遵循垂直切片架构的 ASP.NET Core 8 MVC 应用程序。

这是我的控制器代码:

[AllowAnonymous]
[Route("login")]
public class LoginController(IMediator mediator) : Controller
{
  [HttpGet]
  public async Task<IActionResult> Index()
  {
    var viewModel = await mediator.Send(new LoginQuery());

    return View("/Features/Login/Login.cshtml", viewModel);
  }

  [HttpPost]
  public async Task<IActionResult> Login(LoginCommand command)
  {
    if (!ModelState.IsValid)
    {
      return View("/Features/Login/Login.cshtml");
    }
    
    var viewModel = await mediator.Send(command);

    if (string.IsNullOrEmpty(viewModel.Error))
    {
      return RedirectToAction("index", "dashboard");
    }

    return View("/Features/Login/Login.cshtml");
  }
}

这是我的

Login.cshtml
视图文件中的标记:

<form asp-route="login" method="post" class="space-y-6">
  <div>
    <label asp-for="Email" class="block text-sm font-medium leading-6 text-gray-900"></label>
    <div class="mt-2">
      <input asp-for="Email" class="block w-full rounded-md border-0 py-1.5 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"/>
      <span asp-validation-for="Email" class="mt-2 text-sm text-red-600"></span>
    </div>
  </div>

  <div>
    <label asp-for="Password" class="block text-sm font-medium leading-6 text-gray-900"></label>
    <div class="mt-2">
      <input asp-for="Password" class="block w-full rounded-md border-0 py-1.5 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"/>
      <span asp-validation-for="Password" class="mt-2 text-sm text-red-600"></span>
    </div>
  </div>

  <div>
    <button type="submit" class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Sign in</button>
  </div>
</form>

@section scripts {
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.12/jquery.validate.unobtrusive.js"></script>
}

当模型无效时(例如,我提交表单而未提供电子邮件地址),现在我看到以下内容:

current look

我真正想要的是:

desired look

这是所需外观的代码:

<div>
  <label for="email" class="block text-sm font-medium leading-6 text-gray-900">Email</label>
  <div class="relative mt-2 rounded-md shadow-sm">
    <input type="email" name="email" id="email" class="block w-full rounded-md border-0 py-1.5 pr-10 text-red-900 ring-1 ring-inset ring-red-300 placeholder:text-red-300 focus:ring-2 focus:ring-inset focus:ring-red-500 sm:text-sm sm:leading-6" placeholder="[email protected]" value="adamwathan" aria-invalid="true" aria-describedby="email-error">
    <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
      <svg class="h-5 w-5 text-red-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
        <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
      </svg>
    </div>
  </div>
  <p class="mt-2 text-sm text-red-600" id="email-error">Not a valid email address.</p>
</div>

注意 SVG 图标和一堆错误状态的自定义样式。我知道如果我使用 React/Vue 等前端框架,这会容易得多。但我在这里使用传统的 MVC。

考虑到我的限制,实现这种样式的最简单方法是什么?

asp.net-core-mvc tailwind-css .net-8.0 unobtrusive-validation
1个回答
0
投票

我首先在模型中自定义了错误消息

[Required(ErrorMessage = "My custom message")]
,然后使用JavaScript检查验证错误元素的文本内容来动态添加或删除SVG图标,这是我的示例:

public class MyModel
{
   [Required(ErrorMessage = "My custom message")]
      
 public string MyProperty { get; set; }
}

查看:

<form asp-action="Privacy" asp-controller="Home" class="space-y-4">
    <div class="form-group">
        <label asp-for="MyProperty" class="block text-gray-700"></label>
        <div class="relative mt-2 rounded-md shadow-sm">
            <div class="relative">
                <input asp-for="MyProperty" class="block w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring focus:border-blue-300" />
                <span class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none input-icon"></span>
            </div>
            <span asp-validation-for="MyProperty" class="block text-red-600 mt-1 validation-error"></span>
        </div>
    </div>
    <input type="submit" value="Submit" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-700" />
</form>

@section Scripts {
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
   
    <script>
        function addValidationIcons() {
            $('.validation-error').each(function () {
                var inputContainer = $(this).siblings('.relative').find('.input-icon');

                if ($(this).text().trim() !== '') {
                    if (!inputContainer.find('svg').length) {
                        let svg = `
                        <svg width="16" height="16" fill="red" class="bi bi-exclamation-circle" viewBox="0 0 20 20">
            <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
        </svg>`;
                        inputContainer.html(svg);
                    }
                } else {
                    inputContainer.find('svg').remove();
                }
            });
        }

        $(document).ready(function () {
            addValidationIcons();

            $('input').on('blur keyup', function () {
                $(this).valid();
                addValidationIcons();
            });
        });
    </script>
}

当我的输入框为空时: enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.