侧边栏折叠一秒钟并在页面加载时扩展 [英] Sidebar collapses for a second and expands on page load
问题描述
我有一个侧边栏,单击按钮即可展开或折叠.现在,我已经成功地将其状态存储在 localStorage
中,并且工作正常,除了有一个小问题.
I have this sidebar which expands or collapses on a button click. Now I've successfully stored it's state in localStorage
and it's working fine except there's a slight issue.
当页面加载且 localStorage
中没有任何状态保存时,边栏折叠
一秒钟,然后扩展
.如果在 localStorage
中没有存储状态,则 Expand
应该是默认状态.我不希望它先折叠然后折叠.我只希望页面使用侧栏 expanded
加载.
When the page loads and there is no state saved in localStorage
, the sidebar collapses
for a split second and expands
. Expand
is supposed to be the default state when there is no state stored in localStorage
. I don't want it to collapse
first and then expand
. I just want the page to load with the sidebar expanded
.
我一直在尝试用自己的代码解决问题.但这没有用,然后我将我的代码与SO的帖子结合在一起.仍然不起作用.
I have been trying to solve the issue with my own code. But it didn't work then I combined my code with of of SO's posts. It still doesn't work.
完整代码: Codepen
下面是代码(请注意, localStorage
在SO中将无法运行):
Here's the code(please note that localStorage
won't work in SO):
$('document').ready(function() {
if (typeof window.isMinified === "undefined") {
window.isMinified = false;
}
const body = $('#body');
$("#sidebar-toggler").on("click", function () {
if (window.isMinified === false) {
// localStorage.setItem('menu-closed', !$(body).hasClass("sidebar-minified"));
body.removeClass("sidebar-minified-out").addClass("sidebar-minified");
window.isMinified = true;
} else {
// localStorage.setItem('menu-closed', !$(body).hasClass("sidebar-minified"));
body.removeClass("sidebar-minified").addClass("sidebar-minified-out");
window.isMinified = false;
}
});
const state = // localStorage.getItem('menu-closed');
if (state === null) {
$(body).removeClass('sidebar-minified');
} else {
const closed = state === "true" ? true : false;
if (!closed) {
$(body).removeClass('sidebar-minified');
}
}
});
#body {
background: #fff;
transition: all 0.3s;
}
aside.left-sidebar{
background-color: #2c0963;
height: 100vh;
}
.sidebar-minified-out .left-sidebar {
width: 180px;
transition: width .3s ease-in;
}
.sidebar-minified .left-sidebar {
width: 75px;
transition: width .3s ease-in;
}
.sidebar-toggle {
font-weight: 300;
font-size: 15px;
cursor: pointer;
height: 30px;
position: absolute;
left: 20%;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body id="body" class="sidebar-minified sidebar-minified-out">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>
推荐答案
您可以通过告诉浏览器仅一次拍摄一次 repaint 来最小化闪烁效果.但是,您的侧边栏
总是有一个初始大小:在您的标记内定义的大小.
You can minimize the the flashing effect, by telling the browser to repaint just only one time, in one shot. BUT there will be always one initial size for Your sidebar
: the size which has been defined inside Your markup.
在我的示例中,我正在使用两个 Observers
来跟踪样式和大小的更改.请注意初始的侧边栏
宽度.您可以将初始侧边栏宽度设置为0,或者不指定它的宽度,或者可以将其样式设置为与扩展侧边栏相同的大小,但是总会有一个初始重新绘制.
In my example, I am using two Observers
to track the style and size changes. Please, note the initial sidebar
width. You may set the initial sidebar width equal to 0, or let it unassigned, or maybe You can style it the same size as Your expanded sidebar, but there will be always an initial repaint.
最后,我坚信您需要从 body
删除两个初始类.
Finally, I strongly believe You need to remove the two initial classes from the body
.
$(function() {
/* avoid SO unsecure operation error */
var storage = (function () {
return {
setItem: function(k,v){try{return localStorage.setItem(k,v)}catch(e){return !1}},
getItem: function(k){try{return localStorage.getItem(k)}catch(e){return null}}
};
})();
log("jQuery DOM Ready");
$("#sidebar-toggler").on("click", function() {
var isMinified = !$("body").hasClass("sidebar-minified-out");
$("body")
.toggleClass("sidebar-minified", !isMinified)
.toggleClass("sidebar-minified-out", isMinified);
storage.setItem('menu-closed', +!isMinified);
});
var closed = +storage.getItem('menu-closed');
log('Closed: ' + !!closed);
$("body")
.addClass(closed ? "sidebar-minified" : "sidebar-minified-out")
.css({"visibility": "visible"});
});
body {
background: #fff;
transition: all 0.3s;
}
aside.left-sidebar{
background-color: #2c0963;
height: 100vh;
}
.sidebar-minified-out .left-sidebar {
width: 180px;
transition: width .3s ease-in;
}
.sidebar-minified .left-sidebar {
width: 75px;
transition: width .3s ease-in;
}
.sidebar-toggle {
font-weight: 300;
font-size: 15px;
cursor: pointer;
height: 30px;
position: absolute;
left: 20%;
top: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sidebar State</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body style="visibility: hidden;">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
<div id="log" style="position:absolute;top:0;right:0;padding:1em;"></div>
<script>
/* only debug functions inside this script block */
function log(msg) {
$("<div>").appendTo("#log").text(msg);
}
var mo = new MutationObserver(function (ml){
for(var m of ml) {
if (m.type == 'attributes') log('Body ' + m.attributeName + ' changed');
}
});
mo.observe(document.getElementsByTagName('body')[0], {attributes: true});
var ro = new ResizeObserver(function (rl){
for(var r of rl) {
var w = r.contentRect.width;
if(w<=75 || w>=180) log('Sidebar width: ' + r.contentRect.width);
}
});
ro.observe(document.getElementsByClassName("left-sidebar")[0]);
</script>
</body>
</html>
如果您查看由观察者记录的消息,您将注意到总是有重新粉刷,如上所述.
If You look at the messages logged by the Observers, You will notice that there is always a repaint, as mentioned above.
在阅读完您之前的问题的此解决方案后:
After reading this solution of Your previous question: Dark mode flickers a white background for a millisecond on reload I believe You can implement Your Sidebar toggler the same way.
您可以将其应用于 html
,而不是将CSS类应用于 body
.这是完整代码:
Instead of applying the CSS class to the body
, You can apply it to the html
. Here is the full code:
HTML
<!DOCTYPE html>
<html>
<head>
<script>
/* Render blocking script */
var c = +localStorage.getItem('menu-closed');
document.documentElement.classList.add(c ? 'sidebar-minified' : 'sidebar-minified-out');
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>
</html>
JS
$(function() {
$("#sidebar-toggler").on("click", function (e) {
var isMinified = !$("html").hasClass("sidebar-minified-out");
$("html")
.toggleClass("sidebar-minified", !isMinified)
.toggleClass("sidebar-minified-out", isMinified);
localStorage.setItem('menu-closed', +!isMinified);
});
});
除了进行一些小改动(我只删除了 #body
id)之外,您的CSS仍将保持不变.
Your CSS will remain untouched beside of a small change (I just only removed the #body
id).
现在,如果您比较 Observed 的更改,您会注意到第二种解决方案(使用 head
中的阻塞JS脚本)仅显示了初始的侧边栏大小,即:最初的重绘已消失:
Now, if You compare the Observed changes, You will notice that the second solution, which is using the blocking JS script in head
, is showing only the initial Sidebar size, i.e.: the initial repaint is gone:
1st solution 2nd solution
==============================================================
Sidebar width: 601 Closed: false
jQuery DOM Ready Sidebar width: 180
Closed: false jQuery DOM Ready
Body class changed
Body style changed
Sidebar width: 180
(信用: Roko C. Buljan ):
更多信息:
以下是有关观察者的一些文档:
Here is some documentation about that Observers:
这篇关于侧边栏折叠一秒钟并在页面加载时扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!