Условные атрибуты HTML с использованием Razor MVC3

100

Переменная strCSSClass часто имеет значение, но иногда бывает пустым.

Я не хочу включать пустой class = "" в HTML этого элемента ввода, что означает, что если strCSSClass пуст, мне вообще не нужен атрибут class =.

Ниже приведен один из способов создания условного атрибута HTML:

<input type="text" id="@strElementID" @(CSSClass.IsEmpty() ? "" : "class=" + strCSSClass) />

Есть ли более элегантный способ сделать это? В частности, тот, в котором я мог бы следовать тому же синтаксису, что и в других частях элемента: class = "@ strCSSClass"?

tony722
источник

Ответы:

160

Вы не слышали об этом от меня, менеджера по работе с Razor, но в Razor 2 (веб-страницы 2 и MVC 4) мы будем иметь условные атрибуты, встроенные в Razor (с момента успешного тестирования MVC 4 RC), так что вы можете просто сказать такие вещи ...

<input type="text" id="@strElementID" class="@strCSSClass" />

Если strCSSClass имеет значение null, атрибут класса вообще не будет отображаться.

СШШШ ... не говори. :)

Эрик Портер
источник
1
Ага, ты определенно не должен принимать мой как ответ. Тем не менее, сегодня нет более чистого способа сделать это (поэтому мы создаем более чистый способ сделать это). Вероятно, самый чистый способ сделать это - использовать Html.TextBox, но в нем есть другой набор менее желательных вещей. :( Рад, что вам понравилось то, что мы добавляем. :)
Эрик Портер
1
Но как сочетать атрибуты Razor с другим текстом? Мне нужно сделать следующее: ... id = "track_@track.ID". Я ожидал чего-то вроде ... id = "track_2", но на выходе получился следующий: ... id = "track_@track.ID" ...
Laserson
2
Вы можете заставить Razor оценивать код, заключив его в скобки. id = "track _ @ (track.ID)"
Эрик Портер,
1
Добавлено примечание о том, что это успешно работает с MVC 4. Если вы используете MVC 3, см. Мой ответ ниже.
AaronLS
4
@ErikPorter, ПОЖАЛУЙСТА, НЕ СМОТРЕТЬ МОЙ HTML !! также смотрите stackoverflow.com/questions/9234467/… это также для другого плохого поведения
eaglestorm
126

Обратите внимание, что вы можете сделать что-то вроде этого (по крайней мере, в MVC3):

<td align="left" @(isOddRow ? "class=TopBorder" : "style=border:0px") >

То, что я считал добавлением кавычек бритвой, на самом деле было браузером. Как указал Ризм при тестировании с MVC 4 (я не тестировал с MVC 3, но предполагаю, что поведение не изменилось), это действительно дает, class=TopBorderно браузеры могут разбирать это нормально. Парсеры HTML несколько снисходительны к отсутствию кавычек атрибутов, но это может сломаться, если у вас есть пробелы или определенные символы .

<td align="left" class="TopBorder" >

ИЛИ

<td align="left" style="border:0px" >

Что не так с предоставлением собственных цитат

Если вы попытаетесь использовать некоторые из обычных соглашений C # для вложенных кавычек, у вас будет больше кавычек, чем вы рассчитывали, потому что Razor пытается их безопасно избежать. Например:

<button type="button" @(true ? "style=\"border:0px\"" : string.Empty)>

Это должно быть оценено как, <button type="button" style="border:0px">но Razor экранирует весь вывод C # и, таким образом, производит:

style=&quot;border:0px&quot;

Вы увидите это, только если посмотрите ответ по сети. Если вы используете инспектор HTML, часто вы фактически видите DOM, а не необработанный HTML. Браузеры анализируют HTML в DOM, и к представлению DOM после анализа уже применены некоторые тонкости. В этом случае браузер видит, что вокруг значения атрибута нет кавычек, и добавляет их:

style="&quot;border:0px&quot;"

Но в инспекторе DOM коды символов HTML отображаются правильно, поэтому вы действительно видите:

style=""border:0px""

В Chrome, если вы щелкните правой кнопкой мыши и выберите «Редактировать HTML», он переключится обратно, чтобы вы могли видеть эти неприятные коды символов HTML, давая понять, что у вас есть настоящие внешние кавычки и внутренние кавычки в кодировке HTML.

Таким образом, проблема с попыткой цитирования самостоятельно заключается в том, что Razor избегает этого.

Если вы хотите полный контроль над котировками

Используйте Html.Raw для предотвращения экранирования кавычек:

<td @Html.Raw( someBoolean ? "rel='tooltip' data-container='.drillDown a'" : "" )>

Отображается как:

<td rel='tooltip' title='Drilldown' data-container='.drillDown a'>

Вышесказанное совершенно безопасно, потому что я не выводлю HTML из переменной. Единственная задействованная переменная - это тернарное условие. Однако имейте в виду, что этот последний метод может привести к определенным проблемам безопасности при построении строк из данных, предоставленных пользователем. Например, если вы создали атрибут из полей данных, созданных из данных, предоставленных пользователем, использование Html.Raw означает, что строка может содержать преждевременное окончание атрибута и тега, а затем начать тег сценария, который что-то делает от имени текущего пользователя, вошедшего в систему. пользователь (возможно, отличный от зарегистрированного пользователя). Возможно, у вас есть страница со списком всех изображений пользователей, и вы настраиваете всплывающую подсказку для имени пользователя каждого человека, и один пользователь назвал себя'/><script>$.post('changepassword.php?password=123')</script> и теперь любой другой пользователь, просматривающий эту страницу, мгновенно меняет свой пароль на пароль, который злоумышленник знает.

AaronLS
источник
Это очень хороший момент! И на самом деле это делает его читабельным и удобным в большинстве ситуаций.
Дмитрий Шевченко
Это то, что я делал в примере в моем вопросе. Спасибо за более подробное объяснение и пример. :)
tony722 01
1
Однако остерегайтесь пробелов. "style = display: none;" отображает как none; = "": = "" style = "display"
wmcainsh
1
Так почему же это не работает re: magic двойные кавычки <span @ (true? "Class = logo-owner": string.Empty) /> Это просто создает <span class = logo-owner />
rism
1
@AaronLS Да, именно так они и есть. Не могу понять, как браузер (Chrome 40 / FF33.1 / IE 10) повлияет на что-либо, поскольку это разметка, сгенерированная сервером, и если да, то почему только эти два атрибута класса, но не для атрибута класса кнопки запроса или даже типа = "button" атрибуты всех трех кнопок. Определенно серверная вещь ИМХО, так как я также могу RDP на пару виртуальных машин Azure, разбросанных по всему миру, для того же результата IE / Firefox / Chrome.
rism
12

Думаю, более удобный и структурированный способ - использовать помощник Html. На ваш взгляд, это может выглядеть так:

@{
 var htmlAttr = new Dictionary<string, object>();
 htmlAttr.Add("id", strElementId);
 if (!CSSClass.IsEmpty())
 {
   htmlAttr.Add("class", strCSSClass);
 }
}

@* ... *@

@Html.TextBox("somename", "", htmlAttr)

Если этот способ будет вам полезен, я рекомендую определить словарь htmlAttrв вашей модели, чтобы ваше представление не нуждалось в каких-либо @{ }логических блоках (будьте более ясными).

Ящур
источник
4
-1, никогда не рекомендую никому вкладывать логику в представления. Представления Thew должны отвечать только за рендеринг. Вместо этого добавьте пример HtmlHelper, и я дам вам +1.
jgauffin
1
Чтобы проверить что-то, я могу использовать блок кода в поле зрения - это быстрее. И я рекомендовал перенести этот блок в модель.
Ящур
3
да, но ответы должны отражать передовой опыт, а не быструю и грязную версию, которая превращает обслуживание кода в кошмар.
jgauffin
@jgauffin Я думаю, что помощник по HTML здесь не нужен. увидеть мой ответ.
gdoron поддерживает Монику
+1 @Yaschur Ваш ответ вдохновляет. Продолжайте хорошую работу. т.е. с помощью функции явного преобразования C # мы можем еще больше улучшить этот ответ. Не весь код нужно было оформить определенным образом. Всегда есть лучший способ, о котором мы не подозреваем. И некоторые проекты выступают за организацию кода. Организация кода - это практика, а не концепции!
Bamboo