自定义组件 vue3+elementPlus

图片预览

javascript 复制代码
<template>
  <el-image class="avatar" :src="baseurl + img" :fit="fit" :style="'width: ' + wid + ';height: ' + hei">
    <template #error>
      <div class="image-slot">
        <span class="iconfont icon-tupian" :style="'font-size: ' + siz + ';color:' + col"></span>
      </div>
    </template>
  </el-image>
</template>
<script setup>
import { ref, defineProps } from "vue";
const props = defineProps({ 
  img: { type: String, required: true, default: '' }, 
  fit: { type: String, required: false, default: 'contain' }, // '' | 'fill 拉伸' | 'contain 等比例缩放完整留白' | 'cover 等比例缩放超出裁剪' | 'none 原始尺寸' | 'scale-down 取尺寸较小的显示方式'
  wid: { type: String, required: false, default: '100%' },
  hei: { type: String, required: false, default: '100%' },
  col: { type: String, required: false, default: '' },
  siz: { type: String, required: false, default: '3em' },
 })

const baseurl = ref(process.env.VUE_APP_BASE_API)

</script>

附件预览

javascript 复制代码
<template>
  <div>
    <el-dialog class="wp80 hp80" :model-value="openDetail" :close-on-click-modal="false" :show-close="false" destroy-on-close>
      <template #header>
        <div class="header-left">
          <el-icon class="header-icon">
            <Document />
          </el-icon>
          <span class="header-title">查看附件</span>
        </div>
        <div class="header-right">
          <el-button type="info" text @click="closeWindow('openDetail', emits, false)">
            <el-icon>
              <Close />
            </el-icon>
          </el-button>
        </div>
      </template>
      <div class="video">
        <div class="flexBox-common" style="align-items: flex-start;">
          <div class="flexBox-common zywjBox" style="flex: 1 1 0%;" v-loading="loading" element-loading-background="rgba(122, 122, 122, 0.8)">
            <embed v-if="dqwj.wjlx==='pdf'" class="teaplan_iframe" :src="baseurl + dqwj.fj" style="position:absolute; left: 0; top: 0;" width="100%" height="100%" type="application/pdf" />
            <video v-else-if="dqwj.wjlx==='mp4'" controls="" autoplay="" name="media" style="width:100%;height:100%;"><source :src="baseurl + dqwj.fj" type="video/mp4"></video>
            <video v-else-if="dqwj.wjlx==='3gp'" controls="" autoplay="" name="media" style="width:100%;height:100%;"><source :src="baseurl + dqwj.fj" type="video/3gpp"></video>
            <img v-else-if="dqwj.wjlx==='gif' || dqwj.wjlx==='jpg' || dqwj.wjlx==='jpeg' || dqwj.wjlx==='png' || dqwj.wjlx==='svg'" :src="baseurl + dqwj.fj" style="width: 100%;height: 100%;object-fit: contain;display: block;-webkit-user-select: none;margin: auto;background-color: hsl(0, 0%, 90%);" :onload="officeJiaZai" />
            <iframe v-else-if="dqwj.wjlx==='txt'" :src="baseurl + dqwj.fj" width='100%' height='100%' frameborder='1' ></iframe>
            <vue-office-docx v-else-if="dqwj.wjlx==='docx'" :src="baseurl + dqwj.fj" style="width: 100%;height: 100%;" @rendered="officeJiaZai" />
            <vue-office-excel v-else-if="dqwj.wjlx==='xlsx'" :src="baseurl + dqwj.fj" style="width: 100%;height: 100%;" @rendered="officeJiaZai" />
            <div v-else style="width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;">当前文件不可预览</div>
          </div>
          <div v-if="listFj" class="zyListBox tree-overflow-x">
            <div class="el-scrollbar" style="height: 100%;">
              <div class="el-scrollbar__wrap">
                <div class="el-scrollbar__view">
                  <div class="zyFileItem " :class="curFile===index?'curFile':''" v-for="(item, index) in listFj" :key="index" @click="wjClick(item, index)"><span class="fileOrder">文件{{ index+1 }}</span><span>{{ item.ymc }}</span></div>
                </div>
              </div>
              <div class="el-scrollbar__bar is-horizontal">
                <div class="el-scrollbar__thumb" style="transform: translateX(0%);"></div>
              </div>
              <div class="el-scrollbar__bar is-vertical">
                <div class="el-scrollbar__thumb" style="transform: translateY(0%);"></div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
import { defineEmits, ref, defineProps, watch } from 'vue'
import { closeWindow } from '@/api/common.js'
import VueOfficeDocx from '@vue-office/docx'
import '@vue-office/docx/lib/index.css'
import VueOfficeExcel from '@vue-office/excel'
import '@vue-office/excel/lib/index.css'

const props = defineProps({
  openDetail: { type: Boolean, required: true },
  row: { type: Object, required: false }
})
const emits = defineEmits(['update:openDetail'])
const listFj = ref([])

const dqwj = ref('')
// 文件点击
const baseurl = ref() // 根路径
const curFile = ref(0)
const loading = ref(false)
const wjClick = (item, index) => {
  dqwj.value = { wjlx: '', fj: '' }
  loading.value = false
  if (item.wjlx === 'docx' || item.wjlx === 'xlsx') {
    loading.value = true
  }
  curFile.value = index
  dqwj.value = item
}
const officeJiaZai = () => {
  loading.value = false
}

watch(
  () => props.openDetail,
  () => {
    if (props.openDetail) {
      baseurl.value = process.env.VUE_APP_BASE_API
      listFj.value = props.row.listFj || []
      if (listFj.value.length) {
        listFj.value.forEach((element) => {
          element.wjlx = element.fj.substring(element.fj.lastIndexOf('.') + 1)
          element.ymc = element.fj.substr(element.fj.lastIndexOf('/') + 1)
        })
        dqwj.value = props.row.listFj[0]
      }
    }
  },
  { deep: true, immediate: true }
)
</script>
<style lang="less" scoped>

.video {
  width: 100%;
  height: 100%;
  border: 1px solid #ccc;
  .flexBox-common {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: justify;
    -ms-flex-pack: justify;
    justify-content: space-between;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    height: 100%;
    .zywjBox {
      height: 100% ;
      width: calc(100% - 240px);
      // background: #404040;
      .teaplan_iframe {
        height: 100%;
        width: 100%;
      }
    }

    .zyListBox {
      width: 240px;
      background: #f7f7f7;
      height: 100%;
      margin-left: 10px;
      padding: 0 10px;
      .tree-overflow-x .el-scrollbar__wrap {
        overflow-x: hidden !important;
        padding-right: 10px;
      }
      .curFile {
        color: #1890ff;
        font-weight: bold;
      }
      .zyFileItem {
        word-wrap: break-word;
        word-break: break-all;
        line-height: 25px;
        border-bottom: 1px solid #eee;
        padding: 10px 0;
        font-size: 15px;
        cursor: pointer;
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        .fileOrder {
          font-weight: bold;
          margin-right: 10px;
        }
      }
    }
  }
}
</style>

富文本预览

javascript 复制代码
<template>
  <div v-dompurify-html="msg" @click="handleClick"></div>
</template>

<script setup>
import { ref, defineProps, watch } from 'vue'
import { downloadImage } from '@/utils/requestDownload'

const props = defineProps({
  msg: { type: String, required: true }
})

const handleClick = (event) => {
  const clickedElement = event.target
  // 检查点击的元素是否为你想处理的标签
  if (clickedElement.className.toLowerCase() === 'fujian') {
    // 处理按钮点击事件
    const url = clickedElement.getAttribute('title')
    const title = url.substr(url.lastIndexOf('/') + 1)
    downloadImage(url, title)
  }
}

</script>
<style lang="less" scoped>
img {
  width: 100%;
}
</style>

分页

javascript 复制代码
<template>
  <div class="paging">
    <el-pagination
      v-model:currentPage="currentPage"
      v-model:page-size="pageSize"
      :page-sizes="pageSizes"
      :pager-count="pagerCount"
      :background="background"
      :layout="layout"
      :total="totals"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      >
    </el-pagination>
    <el-link class="ml10" :underline="false" @click="shuaXinClick"><el-icon><RefreshRight /></el-icon></el-link>
  </div>
</template>

<script setup>
import { ref, watch, defineEmits, defineProps } from 'vue'

const props = defineProps({
  pagination: {
    type: Object,
    required: false
  }
})
const emits = defineEmits(['ReturnData'])

const background = ref(true) // 按钮背景
const currentPage = ref(1) // 当前页
const pageSize = ref(100) // 每页显示条数
const pageSizes = ref([100, 200, 300, 400, 500]) // 每页显示个数选择器
const totals = ref(0) // 总条数
const pagerCount = ref(7) // 最大页码按钮数 数值范围:5 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | 21
const layout = ref('sizes, prev, pager, next, jumper, total') // 组件布局: 每页显示 | 上一页 | 页码 | 下一页 | 跳页 | 总条数

// 每页条数
const handleSizeChange = (val) => {
  emits('ReturnData', currentPage.value, val)
}
// 当前页
const handleCurrentChange = (val) => {
  emits('ReturnData', val, pageSize.value)
}
// 刷新
const shuaXinClick = () => {
  emits('ReturnData')
}

watch(() => props.pagination, () => {
  if (props.pagination) {
    background.value = props.pagination.background !== false // 按钮背景
    currentPage.value = props.pagination.pageNo || 1 // 当前页
    pageSize.value = props.pagination.pageSize || 100 // 每页显示条数
    pageSizes.value = props.pagination.pageSizes || [100, 200, 300, 400, 500] // 每页显示个数选择器
    totals.value = parseInt(props.pagination.total) || 0 // 总条数
    pagerCount.value = props.pagination.pagerCount || 7 // 最大页码按钮数
    layout.value = props.pagination.layout || 'sizes, prev, pager, next, jumper, total' // 组件布局
  }
}, { deep: true, immediate: true })

</script>
<style lang="less" scoped>
.el-pagination {
  padding-left: 0;
}
</style>
相关推荐
程序员博博2 小时前
这才是vibe coding正确的打开方式 - 手把手教你开发一个MCP服务
javascript·人工智能·后端
piaoroumi2 小时前
UVC调试
linux·运维·前端
前端不太难2 小时前
RN 调试效率低,一点小改动就需要重新构建?解决手册(实战 / 脚本 / Demo)
前端·react native·重构
是谁眉眼2 小时前
vue环境变量
前端·javascript·vue.js
3秒一个大2 小时前
JSX 基本语法与 React 组件化思想
前端·react.js
鹏北海-RemHusband2 小时前
Vue 组件解耦实践:用回调函数模式替代枚举类型传递
前端·javascript·vue.js
用户6600676685392 小时前
斐波那契数列:从递归到缓存优化的极致拆解
前端·javascript·算法
NuLL2 小时前
异步并行任务执行工具
javascript
海上彼尚2 小时前
vite+vue3 ssg预渲染方案
前端·javascript·vue.js