返回博客

Element UI el-input readonly 灰底失效:inline style 只到外层 div,::v-deep 才能穿进去

某后台管理系统里有一个弹窗,其中有个字段是"系统自动填入、用户不可编辑"的场景。开发给 <el-input> 加了 readonly 属性,又顺手在 style 里写了灰底色,期待用户看一眼就知道这个框不能改——结果验收时用户反馈"和正常输入框没任何区别",用手点了好几次才发现不能编辑。

现象

<!-- 开发以为这样就有灰底了 -->
<el-input v-model="fieldValue" readonly style="background-color: #f5f7fa;" />

浏览器渲染出来是白底,cursor 也没变,与可编辑 input 视觉上毫无差异。即便换成 scoped style 直接写:

/* scoped 里这样写也不生效 */
.el-input__inner {
  background-color: #f5f7fa;
}

依然无效。

根因

el-input 本质是一个 wrapper 组件,其模板大致是:

<div class="el-input">
  <input class="el-input__inner" />
</div>

inline style 经 Vue 的 attribute fallthrough 机制,只落到根元素——也就是外层 <div class="el-input">不会下传到内部的 <input> 元素。Element UI 在 el-input__inner 上自带 background: #fff 等完整样式,优先级足以覆盖外层 div 上那个 background。

第二个坑是 Vue 2 scoped style 的 data-v 隔离。Vue 2 编译时给 scoped 选择器追加 [data-v-xxxxxx] attribute selector,但 element-ui 内部生成的 input 元素上没有当前组件的 hash 属性,导致选择器完全命中不到。

坑:两层墙把你挡死
  1. inline style / 非 scoped 给外层 div → 被 .el-input__inner 自带样式覆盖
  2. scoped style 直接写 .el-input__inner → data-v hash 不匹配,选择器失效

两条路都走不通,背景色永远白底。

正解

用自定义 class 做范围限定,再用 ::v-deep 穿透 scoped 隔离,直接命中内层 input:

<template>
  <el-input v-model="fieldValue" readonly class="my-readonly" />
</template>
 
<style scoped>
::v-deep .my-readonly .el-input__inner {
  background-color: #f5f7fa;
  color: #606266;
  cursor: not-allowed;
}
</style>
正解:自定义 class + ::v-deep 穿透到 .el-input__inner
  • <el-input> 加自定义 class(my-readonly)做范围限定,防止污染同页其它 input
  • ::v-deep 是 Vue 2 scoped 提供的穿透标记,它后面的选择器跳过 data-v 限制,以普通 CSS 匹配子组件内部 DOM
  • 真正要改的是 .el-input__inner,不是外层 .el-input
  • 顺手加 cursor: not-allowed 比单纯灰底更直观——鼠标悬停即反馈
Vue 3 / 旧项目兼容写法
  • Vue 3:改用 :deep(.my-readonly .el-input__inner)
  • 更老的项目:可能用 /deep/>>> 穿透语法,效果相同
  • 不要用全局非 scoped style(去掉 scoped 属性)来绕过问题——会影响整站所有 input

踩坑备忘:readonly vs disabled

容易误用 :disabled="true" 替代 readonly——element-ui 2.x 的 disabled 确实自带灰化样式,视觉上"好像对了",但语义错了:disabled 字段在 HTML 表单提交时不参与提交,而 readonly 才是"不可编辑但参与提交"的正确语义。如果这个字段的值需要被后端接收,绝对不能用 disabled。

一句话外卖

el-input 是 wrapper 组件,inline style 只到外层 div;要改内层 input 的外观,必须自定义 class + ::v-deep .your-class .el-input__inner,这是 Vue 2 scoped + Element UI 组件封装双重隔离下的唯一可靠解法。