问题
在MVC的view页面上,我们虽然可以通过给html attribute手写new { @placeholder = "something" }来增加placeholder属性,但这样做对于MVC3框架而言不是非常地道。一个比较好的办法是通过拓展MVC,来增加一个DataAnnotation属性,最终在Model中指定PlaceHolder。下面的方法是我在stackoverflow网站上撸到的,稍作修改并测试后发现非常牛逼,分享给大家。
解决方法
首先,我们要码一个PlaceHolderAttribute类,让它继承Attribute, IMetadataAware两个接口。注意类名是包含Attribute后缀的,但最终使用的时候是只取PlaceHolder这个名字的。(这个机制是.NET自己撸的,我们不用管)
public class PlaceHolderAttribute : Attribute, IMetadataAware
{
private readonly string _placeholder;
public PlaceHolderAttribute(string placeholder)
{
_placeholder = placeholder;
}
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["placeholder"] = _placeholder;
}
}
这个类你可以丢在类库里或MVC网站项目文件夹里,最后要注意一下引用和命名空间。我的习惯是把这些Attribute类都放在网站下的Infrastructures文件夹中。
但现在还不够,我们必须自定义一个PlaceHolder的显示模板。建一个string类型的显示模板,放到“~/Views/Shared/EditorTemplates/string.cshtml”里:
@{
var placeholder = string.Empty;
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("placeholder"))
{
placeholder = ViewData.ModelMetadata.AdditionalValues["placeholder"] as string;
}
}
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { placeholder = placeholder })
这个模板可以根据你的需求充分自定义。
接下来,我们就可以在Model中用这个placeholder特征了:
Model:
public class MyModel
{
[PlaceHolder("Enter title here")]
public string Title { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new MyModel();
return View(model);
}
View:
@model MVCPlaceHolderDemo.Models.MyModel
<p>
@Html.EditorFor(x => x.Title)
</p>
最后效果如下:
为了兼容不同浏览器,我们还需要先检查一下浏览器是否支持PlaceHolder属性,如果不行就用JQuery加上。配合MVC3默认模板里自带的Modernizr,可以在layout页面加上这段脚本:
$(document).ready(function () {
if (!Modernizr.input.placeholder) {
$("input").each(
function () {
if ($(this).val() == "" && $(this).attr("placeholder") != "") {
$(this).val($(this).attr("placeholder"));
$(this).focus(function () {
if ($(this).val() == $(this).attr("placeholder")) $(this).val("");
});
$(this).blur(function () {
if ($(this).val() == "") $(this).val($(this).attr("placeholder"));
});
}
});
}
});
这样就可以兼容了~
Comments