普通视图

发现新文章,点击刷新页面。
今天 — 2026年3月12日首页

vue2升级vue3:图片点击预览出现样式错乱

作者 lemon_yyds
2026年3月12日 10:14

表格内的图片点击预览出现样式错乱

image.png

表格里的图片预览后,预览层只显示在表格区域里,没有覆盖整个页面,而是被页面容器“裁剪”了,看起来像是只在表格区域中间显示一块

这在 Element Plus 的 el-image 预览里是一个比较常见的问题,原因通常是:

1️⃣ 父容器有 transform / overflow 导致层级被限制

很多后台布局(如 el-table 外层、dialogdrawerlayout)会有:

overflow: hidden;
transform: translate3d(...);

这样会导致 fixed / teleport 的层被限制在父容器内

所以预览层就不会覆盖整个页面,而是被裁剪。

2️⃣ preview-teleported 没有开启(Element Plus 关键属性)

Element Plus 中,图片预览需要开启 teleport 到 body

你现在的代码:

<el-image
  class="table-image-preview"
  style="width: 90px; height: 50px"
  :src="scope.row.appendixFiles[0].fullUrlShow"
  :preview-src-list="scope.row.imgList"
  :append-to-body="true"
  fit="cover"
>

append-to-body 其实 不是 el-image 的属性

正确写法应该是:

<el-image
  class="table-image-preview"
  style="width: 90px; height: 50px"
  :src="scope.row.appendixFiles[0].fullUrlShow"
  :preview-src-list="scope.row.imgList"
  preview-teleported
  fit="cover"
/>

✅ 改成这样

<el-image
  class="table-image-preview"
  style="width: 90px; height: 50px"
  :src="scope.row.appendixFiles[0].fullUrlShow"
  :preview-src-list="scope.row.imgList"
  :preview-teleported="true"
  fit="cover"
/>

3️⃣ 如果还不行,再检查这个 CSS

某些布局会有:

.el-table__body-wrapper {
  overflow: hidden;
}

可以测试:

.el-table {
  overflow: visible;
}

不过 一般 preview-teleported 就能解决


📌 最推荐写法(完整)

<el-table-column label="图片" align="center" min-width="90px">
  <template #default="scope">
    <div v-if="scope.row.appendixFiles?.length">
      <el-image
        style="width:90px;height:50px"
        :src="scope.row.appendixFiles[0].fullUrlShow"
        :preview-src-list="scope.row.imgList"
        :preview-teleported="true"
        fit="cover"
      />
    </div>
  </template>
</el-table-column>

💡 额外建议(企业项目常用)

如果你的 imgList 其实只有一张,可以这样写更安全:

:preview-src-list="[scope.row.appendixFiles[0].fullUrlShow]"

避免 imgList undefined。

vue 2 升级vue3 : element ui 校验红色高亮失去效果

作者 lemon_yyds
2026年3月12日 10:09

element ui 校验红色高亮失去效果

先看代码


// vue2 

.xxxstylename ::v-deep .el-input-number.is-error .el-input__inner {

border-color: #f56c6c;}
// vue3

.xxxstylename :deep(.el-input-number.is-error .el-input__wrapper) {

box-shadow: 0 0 0 1px #f56c6c inset;

}

第一行 ::v-deep 是 Vue 2 中的写法,而第二行 :deep() 是 Vue 3 中推荐的写法

核心对比:

特性 ::v-deep (第一行) :deep() (第二行)
语法形式 伪元素选择器 (Pseudo-element) 伪类函数 (Pseudo-class function)
主要适用 Vue 2 (配合 SCSS/Less 等预处理器) Vue 3 (官方推荐)
兼容性 Vue 3 中仍可用,但已不推荐 Vue 2 中不可用
代码风格 写法相对自由 语法更严谨,将穿透的选择器包裹在函数内

🔍 核心原因分析

Element UI (Vue 2) 的结构逻辑

在 Vue 2 的 Element UI 中,.el-input__inner 就是那个真正的 <input> 标签。

  • DOM 结构.el-input > .el-input__inner (<input>)
  • 样式逻辑:边框 (border) 是直接画在 .el-input__inner 这个 input 元素上的。
  • 你的代码.el-input__inner { border-color: #f56c6c; } —— 有效,因为直接修改了 input 的边框属性。

Element Plus (Vue 3) 的结构逻辑

在 Vue 3 的 Element Plus 中,引入了一个新的概念 .el-input__wrapper 作为视觉容器,而 .el-input__inner 变成了一个透明的“内容层”。

  • DOM 结构.el-input > .el-input__wrapper > .el-input__inner (<input>)

  • 样式逻辑

    • .el-input__inner:默认是透明的(无背景、无边框)。它的作用仅仅是承载文字内容。
    • .el-input__wrapper:负责所有的视觉样式。边框是通过给这个容器添加 box-shadow: inset (内阴影) 来模拟的。
  • 你的代码

    • .el-input__inner { border-color: ... } —— 无效。因为这个 input 元素本身已经没有边框了,它是透明的,你给它加边框在视觉上根本看不到。
    • .el-input__wrapper { box-shadow: ... } —— 有效。因为这才是真正绘制边框的地方。

这并非是 Vue 2 和 Vue 3 的区别,而是 Element UI (Vue 2)  和 Element Plus (Vue 3)  这两个组件库在底层 DOM 结构上的重大变化导致的。

简单来说:Element Plus 废弃了 .el-input__inner 直接控制边框的方式,改用 .el-input__wrapper 阴影来绘制边框。

📌 总结

你遇到的现象完全正常,这是因为 Element Plus 改变了实现方式。

  • Vue 2 (Element UI) :边框属于  .el-input__inner (直接改 border)。
  • Vue 3 (Element Plus) :边框属于  .el-input__wrapper (通过改 box-shadow 模拟)。

所以,在 Vue 3 项目中,如果你想修改输入框的边框颜色(例如错误状态),必须针对 .el-input__wrapper 的 box-shadow 属性进行操作,直接修改 .el-input__inner 的 border 是不起作用的。

昨天以前首页

《vue 2 升级vue3 父组件 子组件 传值: value 和 v-model

作者 lemon_yyds
2026年3月4日 18:09

🧩 v-model 与 value 的关系

当你在一个原生 <input> 上使用 v-model 时,Vue 会将其展开为以下代码:

html

预览

1<!-- 你写的代码 -->
2<input v-model="message">
3
4<!-- Vue 展开后的代码 -->
5<input :value="message" @input="message = $event.target.value">

可以看到,v-model 自动利用了 value 属性来展示数据,并监听 input 事件来更新数据。

🆚 Vue 2 与 Vue 3 的核心区别

1. 响应式原理的变革 (根本原因)

这是导致所有行为差异的根源。

  • Vue 2: 使用 Object.defineProperty。它只能劫持对象的已有属性,无法检测到对象属性的动态添加或删除5。
  • Vue 3: 使用 Proxy。它代理整个对象,可以检测到对象属性的任意变化(增、删、改)25。

2. 组件上 v-model 的默认行为

这是你在开发中感受最明显的区别,尤其是在封装自定义组件时。

表格

特性 Vue 2 Vue 3
默认 Prop value modelValue
默认事件 input update:modelValue
多 Model 支持 不支持,需使用 .sync 修饰符 原生支持多个 v-model

代码对比:

  • Vue 2 中的组件使用

    html

    预览

    1<!-- 父组件 -->
    2<MyComponent v-model="title" />
    3
    4<!-- MyComponent 内部 -->
    5<template>
    6  <!-- 接收 value,触发 input -->
    7  <input :value="value" @input="$emit('input', $event.target.value)" />
    8</template>
    9<script>
    10export default {
    11  props: ['value'] // 默认接收 value
    12}
    13</script>
    
  • Vue 3 中的组件使用

    html

    预览

    1<!-- 父组件 -->
    2<MyComponent v-model="title" />
    3
    4<!-- MyComponent 内部 -->
    5<template>
    6  <!-- 接收 modelValue,触发 update:modelValue -->
    7  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
    8</template>
    9<script setup>
    10defineProps(['modelValue']) // 默认接收 modelValue
    11</script>
    

3. v-model 修饰符与多绑定

Vue 3 的 v-model 变得更加强大和灵活。

  • 多个 v-model:Vue 3 允许你在同一个组件上绑定多个 v-model,通过参数名区分14。

    html

    预览

    1<!-- Vue 3 语法 -->
    2<UserEditor 
    3  v-model:name="userName" 
    4  v-model:age="userAge"
    5/>
    

    这在 Vue 2 中是无法直接实现的,通常需要配合 .sync 修饰符来模拟。

  • 自定义修饰符:Vue 3 支持更灵活的修饰符扩展2。

4. 在原生元素上的表现

对于原生的 <input><textarea><select> 等元素,v-model 的用法在 Vue 2 和 Vue 3 中基本一致,都用于简化双向绑定的代码。主要区别体现在自定义组件的封装上。


💡 总结与迁移建议

  1. 核心变化:Vue 3 将组件 v-model 的默认 prop 从 value 改为了 modelValue,事件从 input 改为了 update:modelValue
  2. 迁移注意:当你将 Vue 2 项目升级到 Vue 3 时,所有自定义表单组件如果依赖默认的 v-model 行为,都需要将 props 中的 value 改为 modelValue,并将 $emit('input') 改为 $emit('update:modelValue')1。
  3. 兼容写法:如果你在 Vue 3 中需要兼容旧的组件库(如 Ant Design Vue),它们可能仍然使用 value prop,这时你需要显式地使用 v-model:value 来绑定,而不是简写的 v-model3。
❌
❌