去掉textarea标签右下角的斜杠:textarea { resize:none }

本文介绍了如何通过CSS样式设置来禁用HTML中textarea标签的大小调整功能,具体讲解了resize属性的使用方法,包括none、both、horizontal和vertical四个值的含义。

1、去掉textarea标签右下角的斜杠:
在这里插入图片描述

	textarea {
		resize:none;
	}

textarea 默认的 textarea { resize:both } ,即拖拽右下角斜杠时可以调整大小的。

描述
none用户无法调整元素的尺寸。
both用户可调整元素的高度和宽度。
horizontal用户可调整元素的宽度。
vertical用户可调整元素的高度
<template> <div class="app-container"> <!-- 搜索区域 --> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <el-form-item label="接收人" prop="receiverId"> <el-select v-model="queryParams.receiverId" placeholder="请选择" clearable filterable style="width: 150px"> <el-option v-for="user in userList" :key="user.id" :label="user.nickName" :value="user.id" /> </el-select> </el-form-item> <el-form-item label="发送时间" prop="createdAt"> <el-date-picker v-model="queryParams.createdAt" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['mod:im_mes:add']">发起聊天</el-button> </el-form-item> </el-form> <div class="chat-container"> <!-- 联系人列表 --> <div class="contact-list"> <!-- 当前用户信息 --> <div class="current-user"> <img :src="currentUser.avatar || options.img" class="avatar" /> <div class="user-info"> <span class="dept-name">{{ currentUser.deptName }}</span> <span class="user-name">{{ currentUser.nickName }}</span> </div> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> </div> <div class="contact-header">会话列表</div> <div v-for="contact in contactList" :key="contact.id" class="contact-item" :class="{ active: activeContact === contact.id }" @click="selectContact(contact)"> <img v-if="contact.avatar" :src="getFullAvatarUrl(contact.avatar)" class="avatar-img" /> <div v-else class="avatar">{{ contact.nickName ? contact.nickName.substring(0, 1) : '' }}</div> <div class="contact-info"> <div class="name">{{ contact.nickName }}({{ currentUser.dept.deptName }})</div> <div class="last-msg">{{ contact.lastMsg }}</div> </div> <!-- <div class="time">{{ contact.time }}</div>--> </div> </div> <!-- 聊天区域 --> <div class="chat-area" v-if="activeContact"> <div class="chat-header"> <div class="current-contact"> <div class="avatar">{{ currentContact.nickName ? currentContact.nickName.substring(0, 1) : '' }} </div> <div class="name">{{ currentContact.nickName }}</div> </div> </div> <div class="message-container" ref="messageContainer"> <div v-for="(message, index) in filteredMessages" :key="index" :class="['message', message.senderId === currentUser.userId ? 'sent' : 'received']"> <div class="avatar" v-if="message.senderId !== currentUser.userId"> {{ getContactName(message.senderId).substring(0, 1) }} </div> <div class="message-content"> <!-- 文本消息 --> <div v-if="message.mediaType === 1" class="message-text">{{ message.content }}</div> <!-- 图片消息 --> <div v-else-if="message.mediaType === 2" class="message-image"> <el-image :src="getFileUrl(message.content)" :preview-src-list="[getFileUrl(message.content)]" fit="cover" style="max-width: 200px; max-height: 200px; border-radius: 4px;"></el-image> </div> <!-- 视频消息 --> <div v-else-if="message.mediaType === 3" class="message-video"> <video :src="getFileUrl(message.content)" controls style="max-width: 200px; max-height: 200px; border-radius: 4px;">您的浏览器不支持视频播放</video> </div> <!-- 文件消息 --> <div v-else-if="message.mediaType === 4" class="message-file"> <div class="file-item"> <i class="el-icon-document" style="font-size: 24px; margin-right: 8px;"></i> <div class="file-info"> <div class="file-name">{{ getFileName(message.content) }}</div> <div class="file-size">{{ formatFileSize(message.fileSize) }}</div> </div> <el-button type="text" @click="downloadFile(message.content)" style="margin-left: 10px;">下载</el-button> </div> </div> <!-- 其他类型消息 --> <div v-else class="message-text">{{ message.content }}</div> <div class="message-time">{{ formatTime(message.createdAt) }}</div> </div> <div class="avatar" v-if="message.senderId === currentUser.userId"> {{ currentUser.nickName.substring(0, 1) }} </div> </div> </div> <div class="input-area"> <!-- 文件上传区域 --> <div class="upload-actions"> <el-upload :action="uploadFileUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :show-file-list="false" :headers="headers" :data="{ type: 'image' }"> <el-button size="mini" icon="el-icon-picture" title="上传图片"></el-button> </el-upload> <el-upload :action="uploadFileUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :show-file-list="false" :headers="headers" :data="{ type: 'video' }"> <el-button size="mini" icon="el-icon-video-camera" title="上传视频"></el-button> </el-upload> <el-upload :action="uploadFileUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :show-file-list="false" :headers="headers" :data="{ type: 'file' }"> <el-button size="mini" icon="el-icon-document" title="上传文件"></el-button> </el-upload> </div> <el-input type="textarea" :rows="3" placeholder="请输入消息..." v-model="newMessage" @keydown.enter.native="sendMessage" resize="none"> </el-input> <div class="input-actions"> <el-button type="primary" size="small" @click="sendMessage">发送</el-button> </div> </div> </div> <div class="no-chat" v-else> <div class="no-chat-tip"> <i class="el-icon-chat-line-round"></i> <p>请选择左侧聊天/或在组织中选择人员聊天</p> </div> </div> </div> <!-- 发起聊天对话框 --> <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> <el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form-item label="接收人" prop="receiverId"> <el-select v-model="form.receiverId" placeholder="请选择接收人"> <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId"></el-option> </el-select> </el-form-item> <el-form-item label="内容" prop="content"> <el-input v-model="form.content" type="textarea" placeholder="请输入内容" /> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button type="primary" @click="submitForm">发送</el-button> <el-button @click="cancel">取消</el-button> </div> </el-dialog> </div> </template> <script> import { listIm_mes, addIm_mes, } from "@/im/sys/api/im_mes" import { getUserProfile, listUser } from "@/api/system/user" import { getToken } from "@/utils/auth" import store from "@/store" import dayjs from 'dayjs' export default { name: "Im_mes", data() { return { // 遮罩层 loading: true, // 选中数组 ids: [], // 非多个禁用 multiple: true, // 显示搜索条件 showSearch: false, // 总条数 total: 0, // 消息记录表格数据 im_mesList: [], // 弹出层标题 title: "", // 是否显示弹出层 open: false, // 查询参数 queryParams: { pageNum: 1, pageSize: 100, receiverId: null, senderId: null, createdAt: null, content: null, }, options: { img: store.getters.avatar, }, // 表单参数 form: {}, // 表单校验 rules: { receiverId: [{ required: true, message: "接收人不能为空", trigger: "blur" }], content: [{ required: true, message: "内容不能为空", trigger: "blur" }] }, // 聊天相关数据 userList: [], // 所有用户列表 contactList: [], // 联系人列表 activeContact: null, // 当前选中的联系人ID currentContact: {}, // 当前联系人信息 currentUser: { userId: store.getters.userId, nickName: store.getters.nickName, avatar: store.getters.avatar, deptName: store.getters.dept ? store.getters.dept.deptName : '未知部门' }, // 当前登录用户 newMessage: "", // 新消息内容 pollInterval: null, // 轮询定时器 // 文件上传相关 uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", headers: { Authorization: "Bearer " + getToken(), }, uploadingFile: null, // 正在上传的文件信息 } }, computed: { filteredMessages() { if (!this.activeContact || !this.currentUser.userId) return []; return this.im_mesList .filter(msg => { // 添加空值检查 if (!msg || !msg.senderId || !msg.receiverId) return false; return ( (msg.senderId === this.activeContact && msg.receiverId === this.currentUser.userId) || (msg.receiverId === this.activeContact && msg.senderId === this.currentUser.userId) ); }) .sort((a, b) => new Date(a.sendTime || a.createdAt) - new Date(b.sendTime || b.createdAt)); } }, created() { this.getCurrentUser(); this.getUserList(); this.getList(); // 启动轮询,每5秒获取一次新消息 this.pollInterval = setInterval(() => { this.getList(); }, 500000); }, beforeDestroy() { // 组件销毁前清除定时器 if (this.pollInterval) { clearInterval(this.pollInterval); } }, watch: { // 当消息列表更新时,自动滚动到底部 filteredMessages: { handler() { this.$nextTick(() => { this.scrollToBottom(); }); }, deep: true } }, methods: { /** 时间格式处理 */ formatTime(time) { return dayjs(time).format('YYYY-MM-DD HH:mm:ss') }, /** 格式化显示时间(用于联系人列表) */ formatDisplayTime(time) { if (!time) return ''; const now = dayjs(); const messageTime = dayjs(time); const diffDays = now.diff(messageTime, 'day'); if (diffDays === 0) { return messageTime.format('HH:mm'); } else if (diffDays === 1) { return '昨天'; } else if (diffDays < 7) { return `${diffDays}天前`; } else { return messageTime.format('MM-DD'); } }, /** 格式化文件大小 */ formatFileSize(size) { if (!size) return '0 B'; const units = ['B', 'KB', 'MB', 'GB']; let index = 0; let fileSize = size; while (fileSize >= 1024 && index < units.length - 1) { fileSize /= 1024; index++; } return `${fileSize.toFixed(2)} ${units[index]}`; }, /** 获取文件URL - 完整版本 */ getFileUrl(path) { if (!path) return ''; // 如果已经是完整URL,直接返回 if (path.startsWith('http') || path.startsWith('blob:')) return path; // 获取基础API URL(可能只是路径部分) const baseApi = process.env.VUE_APP_BASE_API || ''; // 如果baseApi已经是完整URL,直接拼接 if (baseApi.startsWith('http')) { const normalizedPath = path.startsWith('/') ? path : '/' + path; return baseApi + normalizedPath; } // 如果baseApi只是路径部分,需要拼接当前域名 const protocol = window.location.protocol; const hostname = window.location.hostname; const port = window.location.port ? `:${window.location.port}` : ''; // 构建完整的基础URL const fullBaseUrl = `${protocol}//${hostname}${port}${baseApi}`; // 确保路径格式正确 const normalizedPath = path.startsWith('/') ? path : '/' + path; return fullBaseUrl + normalizedPath; }, /** 获取文件名 */ getFileName(path) { if (!path) return '未知文件'; return path.substring(path.lastIndexOf('/') + 1); }, /** 下载文件 */ downloadFile(path) { const link = document.createElement('a'); link.href = this.getFileUrl(path); link.download = this.getFileName(path); link.style.display = 'none'; document.body.appendChild(link); link.click(); document.body.removeChild(link); }, /** 上传前校验 */ handleBeforeUpload(file) { const fileType = file.type; const isImage = fileType.includes('image'); const isVideo = fileType.includes('video'); const isLt10M = file.size / 1024 / 1024 < 10; if (!isLt10M) { this.$modal.msgError('上传文件大小不能超过 10MB!'); return false; } // 保存当前上传的文件信息 this.uploadingFile = { name: file.name, size: file.size, type: isImage ? 2 : isVideo ? 3 : 4 }; return true; }, /** 上传成功处理 */ handleUploadSuccess(res, file) { if (res.code === 200) { // 自动发送文件消息 this.sendFileMessage(res.fileName, this.uploadingFile.type, this.uploadingFile.size); } else { this.$modal.msgError(res.msg || '上传失败'); } this.uploadingFile = null; }, /** 发送文件消息 */ sendFileMessage(fileName, mediaType, fileSize) { if (!this.activeContact) { this.$modal.msgWarning('请先选择联系人'); return; } const newMsg = { receiverId: this.activeContact, senderId: this.currentUser.userId, content: fileName, room: "default", type: 1, mediaType: mediaType, // 2:图片, 3:视频, 4:文件 fileSize: fileSize, status: 1, createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss'), }; addIm_mes(newMsg).then(response => { try { let responseData; if (response && typeof response === 'object') { responseData = response.data || response.result || response; } let messageToAdd; if (responseData && typeof responseData === 'object') { messageToAdd = { id: responseData.id || `temp-${Date.now()}`, receiverId: responseData.receiverId || this.activeContact, senderId: responseData.senderId || this.currentUser.userId, content: responseData.content || fileName, mediaType: responseData.mediaType || mediaType, fileSize: responseData.fileSize || fileSize, createdAt: responseData.createdAt || responseData.sendTime || newMsg.createdAt, ...responseData }; } else { messageToAdd = { id: `temp-${Date.now()}`, ...newMsg, isLocal: true }; } this.im_mesList.push(messageToAdd); // 更新联系人最后一条消息 const contact = this.contactList.find(c => c.id === this.activeContact); if (contact) { let lastMsg = ''; if (mediaType === 2) { lastMsg = '[图片]'; } else if (mediaType === 3) { lastMsg = '[视频]'; } else { lastMsg = '[文件] ' + this.getFileName(fileName); } contact.lastMsg = lastMsg; contact.time = this.formatDisplayTime(messageToAdd.createdAt); } this.$nextTick(() => { this.scrollToBottom(); }); } catch (error) { console.error('处理响应时出错:', error); this.$modal.msgError('处理消息时出错'); } }).catch(error => { console.error("发送失败:", error); this.$modal.msgError("发送失败"); }); }, /** 获取头像地址 */ getFullAvatarUrl(avatarPath) { if (!avatarPath) return ''; // 如果已经是完整URL,直接返回 if (avatarPath.startsWith('http')) return avatarPath; // 拼接基础URL(根据您的实际后端地址配置) return process.env.VUE_APP_BASE_API + avatarPath; }, /** 获取当前登录用户信息 */ getCurrentUser() { // 从store获取基本信息 this.currentUser = { userId: store.getters.userId, nickName: store.getters.nickName, avatar: store.getters.avatar, deptName: store.getters.dept ? store.getters.dept.deptName : '未知部门' }; // 如果需要更详细信息,可以调用API getUserProfile().then(response => { if (response.data) { this.currentUser = { ...this.currentUser, ...response.data, deptName: response.data.dept ? response.data.dept.deptName : '未知部门' }; } }).catch(error => { console.error('获取用户信息失败', error); }); }, /** 获取用户列表 */ getUserList() { listUser().then(response => { this.userList = response.rows; // 初始化联系人列表 this.initContactList(); }); }, /** 初始化联系人列表 */ initContactList() { // 从消息记录中提取联系人 const contactMap = {}; this.im_mesList.forEach(msg => { // 对方是发送人 if (msg.senderId !== this.currentUser.userId) { if (!contactMap[msg.senderId]) { const user = this.userList.find(u => u.userId === msg.senderId); contactMap[msg.senderId] = { id: msg.senderId, nickName: user ? user.nickName : '用户' + msg.senderId, avatar: user ? user.avatar : '', lastMsg: this.getLastMessagePreview(msg), time: this.formatTime(msg.createdAt, true) }; } } // 对方是接收人 if (msg.receiverId !== this.currentUser.userId) { if (!contactMap[msg.receiverId]) { const user = this.userList.find(u => u.userId === msg.receiverId); contactMap[msg.receiverId] = { id: msg.receiverId, nickName: user ? user.nickName : '用户' + msg.receiverId, avatar: user ? user.avatar : '', lastMsg: this.getLastMessagePreview(msg), time: this.formatTime(msg.createdAt, true) }; } } }); this.contactList = Object.values(contactMap); }, /** 获取最后一条消息预览 */ getLastMessagePreview(msg) { if (msg.mediaType === 2) { return '[图片]'; } else if (msg.mediaType === 3) { return '[视频]'; } else if (msg.mediaType === 4) { return '[文件] ' + this.getFileName(msg.content); } else { return msg.content; } }, /** 获取消息记录列表 - 优化版本 */ getList() { this.loading = true; listIm_mes(this.queryParams).then(response => { // 处理消息列表,确保文件路径正确 this.im_mesList = response.rows.map(msg => { // 如果是文件类型的消息,确保content字段是完整URL if (msg.mediaType && msg.mediaType !== "text" && msg.content) { console.log('原始content:', msg.content); console.log('VUE_APP_BASE_API:', process.env.VUE_APP_BASE_API); // 如果content不是完整URL,则转换为完整URL if (!msg.content.startsWith('http')) { msg.content = this.getFileUrl(msg.content); console.log('转换后content:', msg.content); } } return msg; }); this.total = response.total; this.loading = false; // 更新联系人列表 this.initContactList(); }).catch(() => { this.loading = false; }); }, // 取消按钮 cancel() { this.open = false; this.reset(); }, // 表单重置 reset() { this.form = { id: null, receiverId: null, senderId: this.currentUser.userId, content: null, createdAt: null, room: "default", type: 1, mediaType: 1, status: 1 }; this.resetForm("form"); }, /** 搜索按钮操作 */ handleQuery() { this.queryParams.pageNum = 1; this.getList(); }, /** 重置按钮操作 */ resetQuery() { this.resetForm("queryForm"); this.handleQuery(); }, // 多选框选中数据 handleSelectionChange(selection) { this.ids = selection.map(item => item.id); this.multiple = !selection.length; }, /** 新增按钮操作 */ handleAdd() { this.reset(); this.open = true; this.title = "发起聊天"; }, /** 提交按钮 */ submitForm() { this.$refs["form"].validate(valid => { if (valid) { this.form.senderId = this.currentUser.userId; this.form.createdAt = dayjs().format('YYYY-MM-DD HH:mm:ss'); addIm_mes(this.form).then(response => { this.$modal.msgSuccess("发送成功"); this.open = false; this.getList(); // 如果这是一个新的联系人,添加到联系人列表 if (!this.contactList.find(c => c.id === this.form.receiverId)) { const user = this.userList.find(u => u.userId === this.form.receiverId); if (user) { this.contactList.push({ id: user.userId, nickName: user.nickName, lastMsg: this.form.content, time: this.formatTime(new Date()) }); } } }); } }); }, // 聊天相关方法 selectContact(contact) { this.activeContact = contact.id; this.currentContact = contact; }, sendMessage() { if (!this.newMessage.trim() || !this.activeContact) return; const newMsg = { receiverId: this.activeContact, senderId: this.currentUser.userId, content: this.newMessage, room: "default", type: 1, mediaType: 1, fileSize: this.newMessage.length, status: 1, createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss'), }; // 保存原始消息内容,以防需要回退 const originalMessage = this.newMessage; addIm_mes(newMsg).then(response => { try { // 处理API响应 let responseData; if (response && typeof response === 'object') { responseData = response.data || response.result || response; } let messageToAdd; if (responseData && typeof responseData === 'object') { // 使用服务器返回的数据 messageToAdd = { id: responseData.id || `temp-${Date.now()}`, receiverId: responseData.receiverId || this.activeContact, senderId: responseData.senderId || this.currentUser.userId, content: responseData.content || originalMessage, createdAt: responseData.createdAt || responseData.sendTime || newMsg.createdAt, ...responseData }; } else { // 创建本地消息 messageToAdd = { id: `temp-${Date.now()}`, ...newMsg, isLocal: true }; } // 添加到消息列表 this.im_mesList.push(messageToAdd); // 清空输入框 this.newMessage = ""; // 更新联系人最后一条消息 const contact = this.contactList.find(c => c.id === this.activeContact); if (contact) { contact.lastMsg = messageToAdd.content; contact.time = this.formatDisplayTime(messageToAdd.createdAt); } // 重新排序消息列表 this.im_mesList = [...this.im_mesList].sort((a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0) ); // 滚动到底部 this.$nextTick(() => { this.scrollToBottom(); }); } catch (error) { console.error('处理响应时出错:', error); this.$modal.msgError('处理消息时出错'); } }).catch(error => { console.error("发送失败:", error); this.$modal.msgError("发送失败"); // 即使API失败,也在本地显示消息 const localMessage = { id: `temp-${Date.now()}`, ...newMsg, isLocal: true, sendStatus: 'failed' }; this.im_mesList.push(localMessage); this.newMessage = ""; }); }, getContactName(contactId) { if (contactId === this.currentUser.userId) return this.currentUser.nickName; const contact = this.userList.find(c => c.userId === contactId); return contact ? contact.nickName : '用户' + contactId; }, scrollToBottom() { const container = this.$refs.messageContainer; if (container) { container.scrollTop = container.scrollHeight; } } } } </script> 以上若依前端代码只要getList后,消息窗口图片就显示为http://127.0.0.1/dev-api/profile/upload/2025/09/12/CN-wp6_20250912112412A010.jpg,正常上传图片或附件都能正常显示,是什么问题,请给出修改后的完整代码
最新发布
09-13
### 隐藏 HTML 中 `textarea` 的右下角调整大小控件或滚动条 为了实现隐藏 `textarea` 的右下角调整大小控件以及滚动条的功能,可以采用 CSS 来完成这一需求。以下是具体的解决方案: #### 移除调整大小控件 通过设置 `resize` 属性为 `none`,可以完全禁用 `textarea` 的手动调整大小功能。 ```css textarea { resize: none; /* 禁用手动调整大小 */ } ``` 此方法能够有效防止用户拖拽右下角的调整大小手柄[^1]。 #### 隐藏滚动条 如果希望隐藏滚动条但仍保留其滚动功能,则可以通过设置 `overflow` 属性来达到目的。例如: ```css textarea { overflow: hidden; /* 完全隐藏滚动条 */ } ``` 当内容超出指定范围时,上述代码会隐藏滚动条并阻止任何滚动行为。若仅想隐藏视觉上的滚动条而保持实际可滚状态,可以尝试以下方式: ```css textarea { overflow-y: scroll; /* 强制显示垂直滚动条(不可见) */ -ms-overflow-style: none; /* IE/Edge 浏览器 */ scrollbar-width: none; /* Firefox 浏览器 */ } /* WebKit 内核浏览器 (Chrome/Safari) 自定义滚动条样式 */ textarea::-webkit-scrollbar { display: none; } ``` 这里 `-ms-overflow-style` 和 `scrollbar-width` 分别用于处理 Internet Explorer/Edge 和 Firefox 下的滚动条表现;而对于基于 WebKit 的现代浏览器如 Chrome 和 Safari,则需要借助伪元素 `::webkit-scrollbar` 将其设为不展示[^4][^5]。 另外需要注意的是,默认情况下 `textarea` 并不会自动带有水平方向的滚动条除非设置了固定宽度且内部文字过长无法折行。因此一般只需关注竖直维度即可[^2]。 综上所述,最终完整的 CSS 示例如下所示: ```css textarea { resize: none; /* 去掉调整大小按钮 */ overflow: hidden; /* 不允许溢出内容显现 */ -ms-overflow-style: none; /* 清除IE/Edge滚动条 */ scrollbar-width: none; /* 对应Firefox的行为 */ /* 针对WebKit内核隐藏滚动条 */ ::-webkit-scrollbar { display: none; } } ``` 以上配置适用于大多数主流桌面端与移动端环境下的跨平台开发场景之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值