```### 代码2:src\views\handle\dataset\add\AddView.vue```vue ``` - CSDN文库",
"datePublished": "2025-07-23",
"keywords": "如下述代码1,是一个弹窗的代码页面(如图1所示),调整一下左侧的"SQL查询",当分辨率高变形的有点厉害了,请参照代码2中的样式所示,请优化"SQL查询"的样式,并完整的写出修改后的代码(不改变代码1中的功能,即"sql查询"框中能够输入sql语句不变)
### 代码1:src\views\handle\dataset\add\AddView.vue
```vue
```
### 代码2:src\views\handle\dataset\add\AddView.vue
```vue
```
",
"description": "文章浏览阅读10次。我们有一个需求:优化Vue组件中SQL查询编辑器的样式,使其在高分辨率下不变形,并参考另一个Vue组件的样式(代码2)实现响应式布局,同时保留原有功能(如SQL输入、验证、执行等)。 步骤: 1. 分析当前SQL查询编辑器组件的样式问题:在高分辨率下发生变形,可能是由于固定宽度、高度或非响应式布局导致"
}
首页如下述代码1,是一个弹窗的代码页面(如图1所示),调整一下左侧的"SQL查询",当分辨率高变形的有点厉害了,请参照代码2中的样式所示,请优化"SQL查询"的样式,并完整的写出修改后的代码(不改变代码1中的功能,即"sql查询"框中能够输入sql语句不变)
### 代码1:src\views\handle\dataset\add\AddView.vue
```vue
<template>
<div class="sql-dataset-container">
<el-container class="layout-container">
<!-- 右侧SQL配置表单 -->
<el-aside width="40%" class="config-aside">
<div class="config-section">
<div class="section-header">
<h2><el-icon><setting /></el-icon> SQL数据集配置</h2>
</div>
<el-form
:model="form"
:rules="rules"
label-position="top"
class="config-form"
ref="formRef"
>
<!-- 数据集名称 - 修改为行内布局 -->
<el-form-item v-if="props.id===''" label="数据集名称" prop="name" class="form-item-card inline-form-item">
<el-input
v-model="form.name"
placeholder="例如: 用户行为分析数据集"
size="large"
:prefix-icon="Document"
/>
</el-form-item>
<!-- SQL编辑器 -->
<el-form-item label="SQL查询" prop="sql" class="form-item-card sql-editor-item">
<div class="sql-editor-container">
<VAceEditor
v-model:value="form.sql"
lang="sql"
theme="github"
style="height: 300px; width: 100%"
:options="{
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
highlightActiveLine: true,
showLineNumbers: true,
tabSize: 2,
}"
/>
<div class="sql-tips">
<el-tag type="info" size="small">
<el-icon><info-filled /></el-icon>
提示: 请确保SQL语法正确且符合数据源规范
</el-tag>
</div>
</div>
</el-form-item>
</el-form>
</div>
</el-aside>
<!-- 左侧数据预览 -->
<el-main class="preview-main">
<div class="preview-section">
<div class="section-header">
<div class="header-left">
<h2><el-icon><data-line /></el-icon> 数据预览</h2>
</div>
<div class="header-right">
<el-button type="warning" plain size="small" @click="emit('cancel')" :icon="Close">取消</el-button>
<el-button type="success" plain size="small"
:disabled="!form.sql" @click="fetchPreviewData" :icon="Refresh">执行SQL预览</el-button>
<el-button type="primary" plain size="small" @click="handleSave" :icon="Check">保存</el-button>
</div>
</div>
<div class="preview-content">
<zr-table :tableModule="tableModule"
/>
</div>
</div>
</el-main>
</el-container>
</div>
</template>
<script setup>
import {ref, reactive, onMounted, getCurrentInstance} from 'vue'
import { VAceEditor } from 'vue3-ace-editor'
import '@/components/CodeEdit/ace-config.js'
import {
Setting,
DataLine,
Document,
Refresh,
Check,
Close,
InfoFilled, Edit, Download
} from '@element-plus/icons-vue'
import ZrTable from "@/components/ZrTable/index.vue";
import {buildFilterSos} from "@/components/ZrTable/table.js";
import {
handleDataSetCreate,
handleDataSetGet,
handleDataSetPreviewData,
handleDataSetReconstruct
} from "@/api/handle/dataset.js";
const { proxy } = getCurrentInstance()
const props = defineProps({
sceneId:{
type: String,
default: '',
},
id:{
type: String,
default: '',
}
})
const emit = defineEmits(['saved', 'cancel'])
const form = ref({
id:props.id,
name: '',
sceneId:props.sceneId,
type:'view',
sql: '',
info:'',
})
//数据预览
const columnsData= ref([])
const queryData = ref([])
const state = reactive({
columns: columnsData, // 表格配置
query: queryData, // 查询条件配置
queryForm: {}, // 查询form表单
loading: false, // 加载状态
dataList: [], // 列表数据
pages:false,
})
const { loading, dataList, columns, pages, query, queryForm } = toRefs(state)
const formRef = ref(null)
// 预览数据
// 传给子组件的
const tableModule = ref({
callback: fetchPreviewData, // 回调,子组件中可以看到很多调用callback的,这里对应的是获取列表数据的方法
// 以下不说了,上面都给解释了
queryForm,
columns,
dataList,
loading,
pages,
query,
})
const rules = reactive({
name: [
{ required: true, message: '请输入数据集名称', trigger: 'blur' },
{ max: 50, message: '名称长度不能超过50个字符', trigger: 'blur' }
],
sql: [
{ required: true, message: '请输入SQL查询语句', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (!value || !value.trim()) {
callback(new Error('SQL不能为空'))
} else if (!value.toLowerCase().includes('select')) {
callback(new Error('SQL必须是SELECT查询语句'))
} else {
callback()
}
},
trigger: 'blur'
}
]
})
async function fetchPreviewData() {
state.loading = true
const valid = await formRef.value.validate()
if (!valid) {
proxy.$modal.msgError("校验错误,请修改好再次执行")
return
}
// 掉自己的接口,切勿复制粘贴
handleDataSetPreviewData({
sql:form.value.sql
}).then((res) => {
if (res.success) {
if(res.data.pageData.length>0){
for (let key in res.data.pageData[0]) {
columnsData.value.push({prop: key, label:key, align: 'center',show:1})
}
}
state.dataList = res.data.pageData
proxy.$modal.msgSuccess('SQL执行成功')
} else {
proxy.$modal.msgError(res.message)
}
})
state.loading = false
}
const handleSave = async () => {
const valid = await formRef.value.validate()
if (!valid) return
form.value.info=JSON.stringify({
sql:form.value.sql
})
const method=form.value.id===""?handleDataSetCreate:handleDataSetReconstruct
method(form.value).then((res) => {
if (res.success) {
emit('saved',{id: res.data })
} else {
proxy.$modal.msgError(res.message)
}
})
}
watch(() => props.id,
(newid, oldid) => {
if (newid !== oldid && newid!=="") { // 引用变化时触发
handleDataSetGet(newid).then((res) => {
if(res.success){
form.value.sql=JSON.parse(res.data.info)?.sql;
}
})
}
},
{ immediate: true } // 注意:不要用 deep: true
);
</script>
<style scoped lang="scss">
.sql-dataset-container {
height: calc(90vh - 60px);
padding: 20px;
background-color: #f5f7fa;
}
.layout-container {
height: 100%;
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
overflow: hidden;
display: flex;
}
.config-aside {
background: #f9fafc;
border-right: 1px solid var(--el-border-color-light);
padding: 24px;
display: flex;
flex-direction: column;
}
.preview-main {
padding: 24px;
background: #fff;
display: flex;
flex-direction: column;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
h2 {
margin: 0;
color: var(--el-text-color-primary);
font-weight: 600;
font-size: 18px;
display: flex;
align-items: center;
gap: 8px;
}
.header-left, .header-right {
display: flex;
align-items: center;
}
}
.preview-content {
flex: 1;
border: 1px solid var(--el-border-color-light);
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.config-form {
flex: 1;
display: flex;
flex-direction: column;
:deep(.el-form-item) {
margin-bottom: 20px;
&.inline-form-item {
:deep(.el-form-item__label) {
display: inline-flex;
align-items: center;
width: auto;
margin-right: 12px;
padding-bottom: 0;
}
:deep(.el-form-item__content) {
display: inline-flex;
flex: 1;
}
}
.el-form-item__label {
font-weight: 500;
padding-bottom: 8px;
color: var(--el-text-color-regular);
font-size: 14px;
}
}
}
.form-item-card {
background: #fff;
padding: 16px;
border-radius: 8px;
border-left: 3px solid var(--el-color-primary);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
}
.sql-editor-item {
flex: 1;
display: flex;
flex-direction: column;
:deep(.el-form-item__content) {
flex: 1;
display: flex;
flex-direction: column;
}
}
.sql-editor-container {
flex: 1;
display: flex;
flex-direction: column;
border: 1px solid var(--el-border-color-light);
border-radius: 4px;
overflow: hidden;
}
.sql-tips {
padding: 8px 12px;
background: var(--el-color-info-light-9);
border-top: 1px solid var(--el-border-color-light);
.el-tag {
width: 100%;
justify-content: flex-start;
.el-icon {
margin-right: 6px;
}
}
}
.form-actions {
margin-top: 24px;
padding-top: 16px;
display: flex;
justify-content: flex-end;
gap: 16px;
border-top: 1px dashed var(--el-border-color);
}
.refresh-btn {
:deep(.el-icon) {
margin-right: 6px;
}
}
@media (max-width: 992px) {
.layout-container {
flex-direction: column;
}
.config-aside {
width: 100% !important;
border-right: none;
border-bottom: 1px solid var(--el-border-color-light);
}
}
</style>
```
### 代码2:src\views\handle\dataset\add\AddView.vue
```vue
<template>
<div class="sql-dataset-container">
<el-container class="layout-container">
<!-- 左侧:数据集名称和SQL查询 -->
<el-aside class="config-aside">
<div class="config-section">
<div class="section-header">
<h2><el-icon><setting /></el-icon> SQL数据集配置</h2>
</div>
<el-form
:model="form"
:rules="rules"
label-position="top"
class="config-form"
ref="formRef"
>
<!-- 数据集名称 -->
<el-form-item v-if="props.id === ''" label="数据集名称" prop="name" class="form-item-card inline-form-item">
<el-input
v-model="form.name"
placeholder="例如: 用户行为分析数据集"
size="large"
:prefix-icon="Document"
/>
</el-form-item>
<!-- SQL编辑器 -->
<el-form-item label="SQL查询" prop="sql" class="form-item-card sql-editor-item">
<div class="sql-editor-container">
<VAceEditor
v-model:value="form.sql"
lang="sql"
theme="github"
style="height: 100%; width: 100%"
:options="{
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
highlightActiveLine: true,
showLineNumbers: true,
tabSize: 2,
}"
/>
<div class="sql-tips">
<el-tag type="info" size="small">
<el-icon><info-filled /></el-icon>
提示: 请确保SQL语法正确且符合数据源规范
</el-tag>
</div>
</div>
</el-form-item>
</el-form>
</div>
</el-aside>
<!-- 右侧:数据预览 -->
<el-main class="preview-main">
<div class="preview-section">
<div class="section-header">
<div class="header-left">
<h2><el-icon><data-line /></el-icon> 数据预览</h2>
</div>
<div class="header-right">
<el-button type="warning" plain size="small" @click="emit('cancel')" :icon="Close">取消</el-button>
<el-button type="success" plain size="small"
:disabled="!form.sql" @click="fetchPreviewData" :icon="Refresh">执行SQL预览</el-button>
<el-button type="primary" plain size="small" @click="handleSave" :icon="Check">保存</el-button>
</div>
</div>
<div class="preview-content">
<zr-table :tableModule="tableModule"
/>
</div>
</div>
</el-main>
</el-container>
</div>
</template>
<script setup>
import {ref, reactive, onMounted, getCurrentInstance, watch} from 'vue'
import { VAceEditor } from 'vue3-ace-editor'
import '@/components/CodeEdit/ace-config.js'
import {
Setting,
DataLine,
Document,
Refresh,
Check,
Close,
InfoFilled, Edit, Download
} from '@element-plus/icons-vue'
import ZrTable from "@/components/ZrTable/index.vue";
import {buildFilterSos} from "@/components/ZrTable/table.js";
import {
handleDataSetCreate,
handleDataSetGet,
handleDataSetPreviewData,
handleDataSetReconstruct
} from "@/api/handle/dataset.js";
const { proxy } = getCurrentInstance()
const props = defineProps({
sceneId:{
type: String,
default: '',
},
id:{
type: String,
default: '',
}
})
const emit = defineEmits(['saved', 'cancel'])
const form = ref({
id:props.id,
name: '',
sceneId:props.sceneId,
type:'view',
sql: '',
info:'',
})
//数据预览
const columnsData= ref([])
const queryData = ref([])
const state = reactive({
columns: columnsData, // 表格配置
query: queryData, // 查询条件配置
queryForm: {}, // 查询form表单
loading: false, // 加载状态
dataList: [], // 列表数据
pages:false,
})
const { loading, dataList, columns, pages, query, queryForm } = toRefs(state)
const formRef = ref(null)
// 预览数据
// 传给子组件的
const tableModule = ref({
callback: fetchPreviewData, // 回调,子组件中可以看到很多调用callback的,这里对应的是获取列表数据的方法
// 以下不说了,上面都给解释了
queryForm,
columns,
dataList,
loading,
pages,
query,
})
const rules = reactive({
name: [
{ required: true, message: '请输入数据集名称', trigger: 'blur' },
{ max: 50, message: '名称长度不能超过50个字符', trigger: 'blur' }
],
sql: [
{ required: true, message: '请输入SQL查询语句', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (!value || !value.trim()) {
callback(new Error('SQL不能为空'))
} else if (!value.toLowerCase().includes('select')) {
callback(new Error('SQL必须是SELECT查询语句'))
} else {
callback()
}
},
trigger: 'blur'
}
]
})
async function fetchPreviewData() {
state.loading = true
const valid = await formRef.value.validate()
if (!valid) {
proxy.$modal.msgError("校验错误,请修改好再次执行")
return
}
// 掉自己的接口,切勿复制粘贴
handleDataSetPreviewData({
sql:form.value.sql
}).then((res) => {
if (res.success) {
columnsData.value = []; // 重置列数据
if(res.data.pageData.length>0){
for (let key in res.data.pageData[0]) {
columnsData.value.push({prop: key, label:key, align: 'center',show:1})
}
}
state.dataList = res.data.pageData
proxy.$modal.msgSuccess('SQL执行成功')
} else {
proxy.$modal.msgError(res.message)
}
})
state.loading = false
}
const handleSave = async () => {
const valid = await formRef.value.validate()
if (!valid) return
form.value.info=JSON.stringify({
sql:form.value.sql
})
const method=form.value.id===""?handleDataSetCreate:handleDataSetReconstruct
method(form.value).then((res) => {
if (res.success) {
emit('saved',{id: res.data })
} else {
proxy.$modal.msgError(res.message)
}
})
}
watch(() => props.id,
(newid, oldid) => {
if (newid !== oldid && newid!=="") { // 引用变化时触发
handleDataSetGet(newid).then((res) => {
if(res.success){
form.value.sql=JSON.parse(res.data.info)?.sql;
}
})
}
},
{ immediate: true } // 注意:不要用 deep: true
);
</script>
<style scoped lang="scss">
.sql-dataset-container {
height: calc(90vh - 60px);
padding: 16px;
background-color: #f5f7fa;
}
.layout-container {
height: 100%;
background: #fff;
border-radius: 8px;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05);
overflow: hidden;
display: flex; /* 使用flex横向布局 */
flex-direction: row; /* 横向排列 */
}
.config-aside {
background: #f9fafc;
border-right: 1px solid var(--el-border-color-light); /* 右侧边框分隔 */
padding: 18px;
display: flex;
flex-direction: column;
width: 50%; /* 左侧占50%宽度 */
min-width: 300px; /* 最小宽度限制 */
}
.preview-main {
padding: 18px;
background: #fff;
display: flex;
flex-direction: column;
flex: 1; /* 右侧占剩余宽度 */
min-width: 300px; /* 最小宽度限制 */
}
.section-header {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
gap: 12px;
h2 {
margin: 0;
color: var(--el-text-color-primary);
font-weight: 600;
font-size: 16px;
display: flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
}
.preview-content {
flex: 1;
border: 1px solid var(--el-border-color-light);
border-radius: 6px;
overflow: hidden;
display: flex;
flex-direction: column;
min-height: 250px;
}
.config-form {
flex: 1;
display: flex;
flex-direction: column;
:deep(.el-form-item) {
margin-bottom: 16px;
}
}
.form-item-card {
background: #fff;
padding: 12px;
border-radius: 6px;
border-left: 2px solid var(--el-color-primary);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
}
.sql-editor-container {
flex: 1;
display: flex;
flex-direction: column;
border: 1px solid var(--el-border-color-light);
border-radius: 4px;
overflow: hidden;
min-height: 220px;
max-height: 400px;
}
.sql-tips {
padding: 6px 10px;
background: var(--el-color-info-light-9);
border-top: 1px solid var(--el-border-color-light);
.el-tag {
width: 100%;
justify-content: flex-start;
font-size: 11px;
padding: 4px 8px;
}
}
/* 响应式调整 */
@media (max-width: 992px) {
.layout-container {
flex-direction: column; /* 小屏幕下改为纵向布局 */
}
.config-aside,
.preview-main {
width: 100%; /* 占满宽度 */
min-width: auto; /* 取消最小宽度限制 */
}
.config-aside {
border-right: none;
border-bottom: 1px solid var(--el-border-color-light); /* 底部边框分隔 */
max-height: 50%; /* 限制最大高度 */
}
.sql-dataset-container {
padding: 12px;
height: auto;
min-height: 100vh;
}
.section-header {
flex-direction: column;
align-items: stretch;
.header-left, .header-right {
width: 100%;
}
.header-right {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
margin-top: 8px;
}
}
.sql-editor-container {
max-height: 250px;
min-height: 180px;
}
}
@media (max-width: 768px) {
.preview-content {
min-height: 200px;
}
.section-header {
gap: 8px;
h2 {
font-size: 15px;
}
}
.header-right {
grid-template-columns: repeat(2, 1fr) !important;
.el-button {
width: 100%;
margin: 0 !important;
}
.el-button:last-child {
grid-column: span 2;
}
}
}
@media (max-width: 480px) {
.sql-dataset-container {
padding: 8px;
}
.config-aside,
.preview-main {
padding: 12px;
}
.sql-editor-container {
min-height: 150px;
max-height: 200px;
}
.form-item-card {
padding: 8px;
}
.el-input,
.el-button {
font-size: 13px !important;
}
}
</style>
```
<think>我们有一个需求:优化Vue组件中SQL查询编辑器的样式,使其在高分辨率下不变形,并参考另一个Vue组件的样式(代码2)实现响应式布局,同时保留原有功能(如SQL输入、验证、执行等)。
步骤:
1. 分析当前SQL查询编辑器组件的样式问题:在高分辨率下发生变形,可能是由于固定宽度、高度或非响应式布局导致。
2. 参考另一个Vue组件的响应式布局(代码2),我们可以从中提取响应式设计的思路,比如使用flex布局、网格布局、相对单位(如百分比、vw/vh)或媒体查询。
3. 修改当前SQL查询编辑器组件的样式,采用响应式设计,确保在不同分辨率下都能正常显示。
假设我们有两个组件:
- 当前需要优化的组件:SqlQueryEditor(可能存在样式问题)
- 参考组件:CodeEditor(具有响应式布局,我们将其样式思路迁移过来)
由于没有提供具体的代码,我将根据常见情况给出建议:
常见响应式布局方法:
- 使用弹性盒子(Flexbox)或网格(Grid)布局,使内部元素可以自适应容器大小。
- 使用相对单位(如%、vw、vh)代替固定像素(px)设置宽度和高度。
- 使用媒体查询(Media Queries)针对不同分辨率调整样式。
- 设置最小宽度(min-width)和最大宽度(max-width)以防止过度拉伸或压缩。
具体优化步骤:
1. 检查SqlQueryEditor组件的根元素和内部结构,确保其容器是响应式的。
例如,将外部容器设置为宽度100%,高度自适应或者使用相对高度。
2. 如果参考组件(CodeEditor)使用了某种布局,我们可以模仿其结构。
假设参考组件使用了如下样式:
```css
.code-editor {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
min-height: 300px; /* 最小高度 */
max-width: 100%;
}
```
那么我们可以对SqlQueryEditor做类似处理。
3. 对于内部元素(如文本编辑区域、按钮组等),同样使用弹性布局,并设置合适的伸缩比例。
4. 注意保留原有功能,我们只修改样式,不改变功能逻辑。
5. 测试:在不同分辨率和设备上测试,确保不变形。
示例代码(假设当前SqlQueryEditor组件的模板结构):
优化前(可能存在的问题):
```vue
<template>
<div class="sql-editor">
<textarea v-model="sqlCode" class="sql-textarea"></textarea>
<div class="buttons">
<button @click="validate">验证</button>
<button @click="execute">执行</button>
</div>
</div>
</template>
<style scoped>
.sql-editor {
width: 800px; /* 固定宽度,可能导致在高分辨率下变形 */
height: 500px;
}
.sql-textarea {
width: 100%;
height: 80%;
}
.buttons {
margin-top: 10px;
}
</style>
```
优化后(参考响应式布局):
```vue
<template>
<!-- 外层使用一个响应式容器 -->
<div class="sql-editor-container">
<div class="sql-editor">
<textarea v-model="sqlCode" class="sql-textarea"></textarea>
<div class="buttons">
<button @click="validate">验证</button>
<button @click="execute">执行</button>
</div>
</div>
</div>
</template>
<style scoped>
.sql-editor-container {
width: 100%; /* 容器宽度100% */
/* 可以根据需要设置最小高度,或者使用padding-bottom等保持比例 */
min-height: 300px; /* 设置一个最小高度 */
}
.sql-editor {
display: flex;
flex-direction: column;
height: 100%; /* 高度填满容器 */
max-width: 100%; /* 防止超出 */
}
.sql-textarea {
flex: 1; /* 文本区域占据剩余空间 */
min-height: 200px; /* 设置最小高度 */
resize: vertical; /* 允许垂直调整大小 */
width: 100%;
}
.buttons {
margin-top: 10px;
text-align: right; /* 按钮靠右 */
}
/* 如果需要,可以添加媒体查询进一步调整 */
@media (min-width: 1200px) {
.sql-editor-container {
padding: 0 10%; /* 在大屏幕上增加内边距,避免过宽 */
}
}
</style>
```
注意:以上代码是示例,实际修改需要根据组件的具体结构和需求调整。
另外,如果参考组件(代码2)有特别好的样式,我们可以直接复制其样式类,然后根据SQL编辑器的特点进行调整。
最后,确保功能不变:我们只修改了样式,没有改动模板中的元素和事件绑定,因此功能应该保持不变。
相关问题:
1. 在Vue组件中,如何确保样式修改不影响组件的功能?
2. 响应式布局中,如何平衡不同分辨率下的显示效果?
3. 除了CSS样式,还有哪些方法可以优化高分辨率下的显示问题?</think>### 优化 Vue 组件中 SQL 查询编辑器的样式方案
#### 核心问题分析
1. **高分辨率变形原因**:固定尺寸单位(如 `px`)、硬编码宽高值、缺乏弹性布局导致元素拉伸变形
2. **响应式需求**:需适配不同屏幕尺寸
3. **功能保留**:SQL 输入、验证、执行等核心功能不变
#### 优化方案(结合引用[2]的响应式思路)
```vue
<template>
<!-- 响应式容器(参考代码2的弹性容器设计) -->
<div class="sql-editor-container">
<!-- 编辑器区域 -->
<div
ref="editor"
class="sql-editor"
contenteditable
@input="handleInput"
></div>
<!-- 功能按钮组(保持原有功能) -->
<div class="action-bar">
<button @click="validateSQL">验证</button>
<button @click="executeSQL">执行</button>
<span v-if="feedbackMessage" :class="feedbackClass">
{{ feedbackMessage }} <!-- 反馈机制(引用[2]) -->
</span>
</div>
</div>
</template>
<script>
export default {
methods: {
handleInput() {
this.$emit('update:sql', this.$refs.editor.innerText)
},
validateSQL() { /* 原有验证逻辑 */ },
executeSQL() { /* 原有执行逻辑 */ }
}
}
</script>
<style scoped>
/* 响应式容器(关键) */
.sql-editor-container {
display: flex;
flex-direction: column;
max-width: 100vw; /* 防止溢出 */
height: 100%;
}
/* 弹性编辑器(核心优化) */
.sql-editor {
flex: 1; /* 占据剩余空间 */
min-height: 150px; /* 最小高度保证 */
max-height: 70vh; /* 限制最大高度 */
padding: 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-family: monospace;
overflow: auto; /* 内容溢出滚动 */
resize: vertical; /* 允许垂直调整 */
background: #f8f9fa;
}
/* 响应式按钮组 */
.action-bar {
display: flex;
gap: 12px;
padding: 10px 0;
flex-wrap: wrap; /* 小屏幕换行 */
}
/* 反馈消息样式(引用[2]的情感化设计) */
.feedback-success {
color: #67c23a;
padding: 4px 8px;
}
.feedback-error {
color: #f56c6c;
padding: 4px 8px;
}
/* 媒体查询适配高分辨率 */
@media (min-width: 1920px) {
.sql-editor {
font-size: 1.1rem; /* 增大字体 */
padding: 20px; /* 增加内边距 */
}
}
</style>
```
#### 关键优化点说明
1. **弹性布局**:
- 使用 `flex: 1` 使编辑器自动填充空间
- `max-width: 100vw` 防止水平溢出
- `max-height: 70vh` 限制高度避免拉伸
2. **响应式策略**:
```css
/* 示例:根据屏幕尺寸动态调整 */
@media (min-width: 1200px) {
.sql-editor { padding: 15px; }
}
@media (min-width: 1920px) {
.sql-editor { font-size: 1.1rem; }
}
```
3. **功能保留技巧**:
- 通过 `contenteditable` + `@input` 实现 SQL 输入
- 按钮事件绑定原有验证/执行方法
- 反馈消息区域(引用[2]的反馈机制)
4. **防变形措施**:
- `resize: vertical` 允许手动调整高度
- `min-height`/`max-height` 双重约束
- `overflow: auto` 保证内容滚动而非容器变形
#### 验证方法
1. 在 4K 屏幕测试容器是否自适应
2. 检查按钮功能是否正常触发
3. 输入超长 SQL 语句验证滚动行为
4. 调整浏览器窗口大小观察布局变化
> 通过组合弹性布局、相对单位和媒体查询,可在保留功能的同时实现响应式适配。建议逐步替换固定尺寸单位为 `%`、`vw`、`vh` 等相对单位,并结合 CSS 变量维护设计一致性[^2]。
相关推荐
t.add_row([1,"程序设计基础",98,2]) t.add_row([2,"大学物理",85,3]) t.add_row([3,"高等数学",91,4]) t.add_row([4,"英语",88,2]) print(t) 输出结果如下: +----+--------------+------+------+ | ... 使用LRU置换算法时,每次置换最近最久未使用的页面。以下是该页面访问序列的内存块状态: 1. 1 缺页 2. 1, 2 缺页 3. 1, 2, 3 缺页 4. 2, 3, 4 缺页 5. 2, 3, 4 命中 6. 1, 3, 4 缺页 7. 1, 2, 4 缺页 8. 2, 4, 3 ...