如何让DIV固定在页面的某个位置而不随着滚动条随意滚动(转)

这里稍微总结一下,那就是利用JavaScript脚本,从浏览器中获取各个关于位置的参数,然后将其计算后,定位在窗体的右下角。可以承认,这个方法确实是比较自然的想法,也是很常见的方法,但是这样的方法有以下几个缺点:

1、使用了大量的计算,每次滚动,都少不了一大堆的运算。
2、使用了JavaScript脚本,脚本这东西受到浏览器的限制,即便没有限制,也同样因为网页的下载模式问题,可能因为脚本下载未完成或者下载失败而致使脚本无法正确运行。
3、条条大路通罗马,但是看看那方块,当快速滚动滚动条的时候,会发现那个可爱的方块抖动地厉害。这也难怪,那么多的计算谁能受得了?
那有没有比较“平静”高效的表示方式呢?比如是否有一种用CSS的方式呢?

首先,我们将目光投向了CSS规范,我想很多人和我一样很快就想到了position属性,说到定位,我们很容易想到这个属性。这个属性一共有四个选项:static、relative、absolute、fixed(详情请点击)。很高兴,我们在阅读了相关的注释后,我们大概能看到fixed是比较符合我们的需求的:

[quote]fixed:

位置被设置为 fixed 的元素,可定位于相对于浏览器窗口的指定坐标。此元素的位置可通过 "left"、"top"、"right" 以及"bottom" 属性来规定。不论窗口滚动与否,元素都会留在那个位置。工作于 IE7(strict 模式)。[/quote]
于是我们很快就有了以下的代码,不过很遗憾,IE中并不能通过严格的测试,但是FireFox中却可以通过测试!
[quote]<html>
<head>
<!--http://volnet.cnblogs.com-->
<title>Only fit FireFox! :(</title>
<!--Some thing about the fixed style!-->
<style type="text/css">
.fixed_div{
position:fixed;
left:200px;
bottom:20px;
width:400px;
}
</style>
</head>
<body>
<div class="fixed_div" style="border:1px solid #200888;">content, I'm content</div>
<div style="height:888px;"></div>
</body>
</html>[/quote]
不管上面上面说的IE7的strict模式,很显然,除了IE7,我们的挑战还有包括IE6在内的一大堆未知的因素。很显然,虽然这个方法通过了FireFox,但我们还是宣告失败了。

难道我们只能使用JavaScript让这一切继续“卡”下去么?(我指的是用JavaScript的时候效果很卡)

当然不行,我们的症结究竟在哪?我们该如何去解除它呢?带着这样的郁闷,我们需要开始新的探险。

HTML究竟是啥?

这个问题换在别的地方问,您可能要搬出一大堆的文档来告诉我HTML的定义,但这里我并不需要那么完整的答案。我们知道HTML是由一大堆的<tag></tag>组成的,而这一大堆的<tag></tag>组合在一起,它们的结构就像一棵树,是的,HTML的代码就是被解释为了一棵树被浏览器所认识。它有一个根,那就是<html></html>节(root),在根节点下常见的节点中,我们通常能见到<head></head>和<body></body>两个节点,它们之下又有……

现在回顾一下我们的问题,我们的问题是我们滚动滚动条的时候我们希望其中的一个指定的div不会跟着滚动条滚动。

那么下面让我们来回答另一个问题,啥是滚动条?

滚动条,顾名思义,就是可以滚动的条(ScrollBar)(废话)。准确地说,滚动条通常是我们在页面的内容超过了浏览器显示框的范围的时候,为了能够让有限的空间展示无限的内容所作出的一个妥协的元素,使用它可以让我们查看当前页面内容之外部分的内容。

说到这里您估计都还很清楚,但既然我说滚动条也是一个元素,那么它是不是也在我们的HTML中呢?又或者它是浏览器的固有的一部分?

如果您觉得它是HTML中的一部分,那么您就对了,因为它是依附容器而存在的,而默认产生滚动条的容器是<body></body>或者<html></html>节,它并不是浏览器固有的一部分,浏览器只是默认完整展示了一整个html文档,并不知道它中间的内容究竟是否需要滚动条的支持。

那么让我们回顾上面的那几行代码吧,假设fixed对您当前(失败)的浏览器无效的话,那么我们来看看它们的结构,外面是html标签,向内是body标签,再向内则是div标签,div标签很明显是它们的一部分,这样假设我们的div标签所设置的定位属性无论如何(四个可能的属性皆没起到什么作用)改变不了自身显示状况。我们能否更换一个思路呢?

刚才我说了,滚动条是容器所固有的,不管是外面那个滚动条,还是里面那个滚动条。那么我能否让这个需要固定的div和那个body或者html容器脱离关系呢?

看到滚动条的控制可以通过CSS的overflow的几个属性来控制,想必大家都不陌生了。(陌生的朋友点击相关链接即可进入查看)

那么我是否可以自己设置两个完全隔离的div来模拟这种场景呢?(虽说是模拟,但是效果一模一样噢~)

[quote]<html>
<head>
<title></title>
<style type="text/css">

html,body {
overflow:hidden;
margin:0px;
width:100%;
height:100%;
}

.virtual_body {
width:100%;
height:100%;
overflow-y:scroll;
overflow-x:auto;
}

.fixed_div {
position:absolute;
z-index:2008;
bottom:20px;
left:40px;
width:800px;
height:40px;
border:1px solid red;
background:#e5e5e5;
}
</style>
</head>

<body>
<div class="fixed_div">I am still here!</div>
<div class="virtual_body">
<div style="height:888px;">
I am content !
</div>
</div>
</body>
</html>[/quote]
分析:

html,body:将默认可能会随机出现的滚动条,完全地隐藏了,这样不管您放了啥内容,它们都不会出来了。

.virtual_body:顾名思义,就是一个假的body了,它被设置为长宽都为100%的,意思就是它利用了所有可视的浏览器窗体显示所有的内容,并垂直允许出现滚动条。

.fixed_div:这下它可以利用绝对值进行定位了,因为在这个场景下,这个页面100%地被那个假冒的body给独霸了,而滚动条反正也出不来,您就可以自认为是在某个点蹲坑了,绝对安全。

想必您通过这些代码已经了解了新的方法不过是将一个div换作了之前的body。
<script setup lang="ts"> import { ref, onMounted } from 'vue'; import { NLayout, NLayoutHeader, NLayoutContent, NLayoutFooter, NIcon, NInput, NInputGroup, NButton, NUpload, NCode, NScrollbar, NEmpty, NConfigProvider // 引入配置提供器 } from 'naive-ui'; import { SearchOutline as SearchIcon } from '@vicons/ionicons5'; import hljs from 'highlight.js/lib/core'; import python from 'highlight.js/lib/languages/python'; import 'highlight.js/styles/github.css'; // 导入github主题 // 注册语言 hljs.registerLanguage('python', python); // 可以在这里注册更多语言,如javascript、typescript等 const searchQuery = ref(''); const fileContent = ref(''); const fileName = ref(''); // 根据文件后缀获取语言类型 const getLanguageByExtension = (filename: string) => { const extension = filename.split('.').pop()?.toLowerCase() || ''; const langMap: Record<string, string> = { 'js': 'javascript', 'jsx': 'javascript', 'ts': 'typescript', 'tsx': 'typescript', 'html': 'html', 'css': 'css', 'json': 'json', 'vue': 'html', 'py': 'python', 'java': 'java', 'c': 'c', 'cpp': 'cpp', 'cs': 'csharp', 'php': 'php', 'rb': 'ruby', 'go': 'go', 'rs': 'rust', 'swift': 'swift', 'kt': 'kotlin', 'sh': 'shell', 'md': 'markdown', 'yaml': 'yaml', 'yml': 'yaml', 'xml': 'xml' }; return langMap[extension] || 'text'; }; const handleFileChange = ({ file }: any) => { const selectedFile = file.file as File; if (selectedFile) { if (!selectedFile.type.startsWith('text/') && !selectedFile.name.match(/\.(js|jsx|ts|tsx|html|css|json|vue|py|java|c|cpp|cs|php|rb|go|rs|swift|kt|sh|md|yaml|yml|xml)$/i)) { window.alert('请选择文本或代码文件'); return; } fileName.value = selectedFile.name; searchQuery.value = selectedFile.name; const reader = new FileReader(); reader.onload = (e: ProgressEvent<FileReader>) => { if (e.target?.result) { fileContent.value = e.target.result as string; } }; reader.readAsText(selectedFile); } }; const handleNext = () => { console.log('下一步操作', fileContent.value); window.alert('进入下一步操作!'); }; </script> <template> <!-- 在n-config-provider中注入hljs --> <n-config-provider :hljs="hljs"> <n-layout class="container"> <!-- 顶部图标 --> <n-layout-header class="header"> <n-icon size="48" color="#2080f0"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/> </svg> </n-icon> <h1 class="title">自动化测试平台</h1> </n-layout-header> <!-- 搜索区域 --> <n-layout-content class="search-section"> <n-input-group> <div class="source-label">Source:</div> <n-input v-model="searchQuery" placeholder="输入文件路径或选择文件" readonly size="large" /> <n-upload action="" :show-file-list="false" @change="handleFileChange" > <n-button type="primary" size="large"> <template #icon> <n-icon><search-icon /></n-icon> </template> 选择文件 </n-button> </n-upload> </n-input-group> </n-layout-content> <n-layout-content class="content-display"> <n-scrollbar style="height: 100%"> <div v-if="fileContent"> <!-- 使用n-code组件,并设置show-line-numbers和word-wrap --> <n-code :code="fileContent" :language="getLanguageByExtension(fileName)" show-line-numbers word-wrap /> </div> <n-empty v-else description="未选择文件" /> </n-scrollbar> </n-layout-content> <!-- 底部操作区域 --> <n-layout-footer class="footer"> <n-button type="primary" size="large" :disabled="!fileContent" @click="handleNext" class="action-button" > 下一步 </n-button> </n-layout-footer> </n-layout> </n-config-provider> </template> <style scoped> .container { height: 100vh; display: flex; flex-direction: column; overflow: hidden; } .header { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; padding: 15px 0; } .title { font-size: 24px; font-weight: bold; margin-top: 8px; color: #333; } .search-section { flex: 0 0 auto; padding: 10px 0 20px; width: 100%; } .n-input-group { display: flex; align-items: center; width: 100%; padding: 0 20px; box-sizing: border-box; } .source-label { font-size: 16px; font-weight: bold; color: #333; white-space: nowrap; margin-right: 12px; } .content-display { flex: 1; min-height: 0; padding: 0 20px; overflow: auto; /* 单一滚动条控制 */ } .code-container { background: #f5f5f5; border-radius: 4px; padding: 15px; max-height: calc(100vh - 250px); /* 动态高度计算 */ } /* 覆盖n-code的样式,确保背景色一致 */ :deep(.n-code) { background: #f5f5f5 !important; padding: 15px; font-size: 15px; line-height: 1.5; max-height: 100%; overflow: auto; } :deep(.n-code-line) { white-space: pre-wrap !important; word-break: break-word !important; } .footer { flex: 0 0 auto; display: flex; justify-content: flex-end; padding: 15px 20px; width: 100%; box-sizing: border-box; } .action-button { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } @media (max-width: 768px) { .search-section, .content-display, .footer { padding-left: 10px; padding-right: 10px; } .n-input-group { flex-direction: column; align-items: flex-start; } .source-label { margin-bottom: 8px; margin-right: 0; } .n-upload { margin-top: 10px; width: 100%; } .n-button { width: 100%; } .action-button { width: 100%; margin-top: 10px; } } </style>我修改样式和布局,这个页面我在鼠标往下滚动滚动条(因为父组件已经有了)如果这个页面再来一黑色的滚动条,特别丑,所以给我修改,使其屏幕上只有一个滚动条
最新发布
10-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值