侧边栏折叠一秒钟,并在页面加载时展开



我有一个侧边栏,它通过单击按钮即可展开或折叠。现在我已经成功地将其状态存储在localStorage中,除了一个小问题外,它工作正常。

当页面加载并且没有localStorage保存状态时,侧边栏会collapses一瞬间并expandsExpand应该是localStorage中没有存储状态时的默认状态。我不希望它先collapse,然后再expand.我只想让页面加载侧边栏expanded.

我一直在尝试用自己的代码解决问题。但是它不起作用,然后我将我的代码与SO的帖子结合起来。它仍然不起作用。

完整代码: 代码笔

这是代码(请注意,localStorage在 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>

您可以通过告诉浏览器一次只重绘一次来最小化闪烁效果。但是您的sidebar总会有一个初始大小:在您的标记中定义的大小。

在我的示例中,我使用两个Observers来跟踪样式和大小更改。请注意初始sidebar宽度。您可以将初始侧边栏宽度设置为等于 0,或者将其取消分配,或者您可以将其样式设置为与展开的侧边栏相同的大小,但总会有初始重绘。

最后,我坚信您需要从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>

编辑:

如果您查看观察者记录的消息,您会注意到总是有重新绘制,如上所述。

阅读了您之前的问题的解决方案后:深色模式在重新加载时闪烁白色背景一毫秒,我相信您可以以相同的方式实现侧边栏切换器。

与其将CSS类应用于body,不如将其应用于html。以下是完整的代码

.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);
});
});

您的 CSS 将在一个小的更改旁边保持不变(我只是删除了#bodyid)。

现在,如果您比较观察到的更改,您会注意到第二个解决方案,即在head中使用阻塞 JS 脚本,仅显示初始侧边栏大小,即:初始重绘消失了:

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):

更多信息:


我的第一个示例中的调试函数仅用于描述浏览器中调整大小和重新样式事件的顺序。以下是有关该观察者的一些文档:

  • 突变观察者
  • 调整观察者大小

正是从 css 的过渡让侧边栏展开。如果您删除转译,您将看到侧边栏在页面加载时立即展开。因此,您应该第一次设置没有过渡的CSS类。

您可以通过 Javascript 禁用转换,然后再次为 click 事件启用它:

JSFIDDLE 演示

首先删除 body 标记中的类:

<body id="body" class="">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>

只需在javascript中更改几行:

$('document').ready(function() {
if (typeof window.isMinified === "undefined") {
window.isMinified = false;
}
const body = $('#body');
$("#sidebar-toggler").on("click", function () {

document.querySelector('.left-sidebar').style.transition = 'inherit';
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.addClass('sidebar-minified');
} else {
const closed = state === "true" ? true : false;
if (!closed) {
body.addClass('sidebar-minified-out');
document.querySelector('.left-sidebar').style.transition = 'none';
}
else {
body.addClass('sidebar-minified');
}
}
});

上述代码中的重要更改是两件事:

// in the clickevent section: change the transistion to default behaviour
document.querySelector('.left-sidebar').style.transition = 'inherit';

根据状态设置正确的类并禁用转换:

// ...
if (state === null) {
body.addClass('sidebar-minified');
} else {
// ...
if (!closed) {
body.addClass('sidebar-minified-out');
document.querySelector('.left-sidebar').style.transition = 'none';
}
else {
body.addClass('sidebar-minified');
}
}

更新***

我重构了代码并对其进行了一点优化。 小提琴 .HTML:

<body id="body">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>

.CSS:

#body {
background: #fff;
transition: all .3s;
}
aside.left-sidebar {
background-color: #2c0963;
height: 100vh;
width: 75px;
}
.sidebar-minified-out .left-sidebar {
width: 180px;
}
.sidebar-transitions .left-sidebar {
transition: width .3s ease-in; 
} 
.sidebar-toggle {
font-weight: 300;
font-size: 15px;
cursor: pointer;
height: 30px;
position: absolute;
left: 20%;
top: 0;
}

.JS:

$('document').ready(function() {
$("#sidebar-toggler").on("click", function () {

localStorage.setItem('menu-closed', $('#body').hasClass('sidebar-minified-out'));
$('#body').addClass('sidebar-transitions').toggleClass('sidebar-minified-out');

});
localStorage.getItem('menu-closed') === "true" ? $('#body').removeClass('sidebar-minified-out') : $('#body').addClass('sidebar-minified-out');
});

如何将动画移动到单独的类中,比如说

.sidebar-animated{
transition: width: 0.3s ease-in;
}

并从其他任何地方删除它,然后通过超时添加该类,因此在转换完成后添加它,您可以使用 useTimeout 和 0 秒,如下所示,

setTimeout(() => {
$('aside').addClass('sidebar-animated')    
},0)

加上CSS使用特异性来达到它的元素,所以

.sidebar-minified-out .left-sidebar {
width: 180px;
}
.sidebar-minified .left-sidebar {
width: 75px;
} 

应该改成这个。

.sidebar-minified .left-sidebar {
width: 75px;
} 
.sidebar-minified-out .left-sidebar {
width: 180px;
}

因为当你在同一个元素上两者都有时,它会采取后者,因为它们具有相同的特异性规则,给它最后一次机会,这是我:D的最后手段。

这足以使其工作

https://codepen.io/menawer_cpe/pen/qBZbEdw

这是一个工作示例, 注意:当侧边栏最初折叠时,您在管理状态时遇到了问题,但这与您如何处理状态有关。

为什么使用0的Timeout?因为它将执行推送到所谓的"事件循环",确保在所有JavaScript正常代码执行后执行。

你可以试试这个:

$('document').ready(function() {
if (window.isMinified === undefined) {
window.isMinified = false;
}
const body = $('#body');
$("#sidebar-toggler").on("click", function() {

$('#body .left-sidebar').removeAttr("style");
if (window.isMinified === false) {

body.removeClass("sidebar-minified-out").addClass("sidebar-minified");
window.isMinified = true;
} else {
body.removeClass("sidebar-minified").addClass("sidebar-minified-out");
window.isMinified = false;
}
});
var firstTime = true;
var sidebar = $('#body aside.left-sidebar');
const state = !(null); //localStorage.getItem('menu-closed');
if (state === null) {
$(body).removeClass('sidebar-minified');
} else {
if (firstTime) {
sidebar.css('transition', 'none');
firstTime = false;
}
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>

最新更新