我正在开发一个遵循垂直切片架构的 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>
}
当模型无效时(例如,我提交表单而未提供电子邮件地址),现在我看到以下内容:
我真正想要的是:
这是所需外观的代码:
<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。
考虑到我的限制,实现这种样式的最简单方法是什么?
我首先在模型中自定义了错误消息
[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>
}