feat(HEL-76): 手机端丝滑度整改②——换页过渡与启动登录反馈

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
施工员
2026-08-24 11:11:17 +08:00
co-authored by multica-agent
parent 7752648e4b
commit a92caa4f3f
4 changed files with 111 additions and 15 deletions
+40 -14
View File
@@ -56,6 +56,17 @@
let internalNav = 0;
let authMode = "login";
const VIEW_MOTION_CLASSES = ["m-motion-fade-in", "m-motion-push-in", "m-motion-pop-in", "m-motion-boot-in"];
function applyViewMotion(motion) {
const view = document.getElementById("m-view");
VIEW_MOTION_CLASSES.forEach(function (cls) {
view.classList.remove(cls);
});
void view.offsetWidth;
view.classList.add(motion || "m-motion-fade-in");
}
function currentHash() {
let hash = window.location.hash || "";
if (!hash || hash === "#" || hash === "#/") return DEFAULT_HASH;
@@ -92,14 +103,14 @@
function navigate(hash) {
stack.push(hash);
setHash(hash);
render();
render("m-motion-push-in");
}
function replace(hash) {
function replace(hash, motion) {
if (stack.length) stack[stack.length - 1] = hash;
else stack.push(hash);
setHash(hash);
render();
render(motion);
}
function resetStack(hash) {
@@ -118,11 +129,11 @@
if (stack.length > 1) {
stack.pop();
setHash(stack[stack.length - 1]);
render();
render("m-motion-pop-in");
return;
}
const parent = parentRoute(currentRoute());
if (parent) replace(parent);
if (parent) replace(parent, "m-motion-pop-in");
}
function switchEntry(key) {
@@ -240,7 +251,7 @@
'<label class="m-form-field"><span>密码</span><input id="m-auth-password" type="password" minlength="8" maxlength="128" autocomplete="current-password" required></label>',
'<label class="m-form-field" id="m-auth-confirm-field" hidden><span>确认密码</span><input id="m-auth-confirm" type="password" minlength="8" maxlength="128" autocomplete="new-password"></label>',
'<p class="m-auth-error" id="m-auth-error" hidden></p>',
'<button class="m-btn-primary" id="m-auth-submit" type="submit">登录</button>',
'<button class="m-btn-primary" id="m-auth-submit" type="submit"><span class="m-btn-spinner" aria-hidden="true" hidden></span><span class="m-btn-label">登录</span></button>',
"</form>",
"</div>"
].join("");
@@ -256,7 +267,8 @@
document.getElementById("m-auth-confirm-field").hidden = authMode !== "register";
document.getElementById("m-auth-confirm").required = authMode === "register";
document.getElementById("m-auth-password").autocomplete = authMode === "register" ? "new-password" : "current-password";
document.getElementById("m-auth-submit").textContent = authMode === "register" ? "注册并进入" : "登录";
const submitLabel = document.querySelector("#m-auth-submit .m-btn-label");
if (submitLabel) submitLabel.textContent = authMode === "register" ? "注册并进入" : "登录";
document.getElementById("m-auth-error").hidden = true;
}
@@ -267,18 +279,29 @@
document.getElementById("m-auth-form").addEventListener("submit", submitAuth);
}
function showAuthError(element, message) {
element.textContent = message;
element.classList.remove("m-motion-fade-in");
void element.offsetWidth;
element.classList.add("m-motion-fade-in");
element.hidden = false;
}
async function submitAuth(event) {
event.preventDefault();
const username = document.getElementById("m-auth-username").value.trim();
const password = document.getElementById("m-auth-password").value;
const errorElement = document.getElementById("m-auth-error");
if (authMode === "register" && password !== document.getElementById("m-auth-confirm").value) {
errorElement.textContent = "两次输入的密码不一致。";
errorElement.hidden = false;
showAuthError(errorElement, "两次输入的密码不一致。");
return;
}
const submit = document.getElementById("m-auth-submit");
const spinner = submit.querySelector(".m-btn-spinner");
const label = submit.querySelector(".m-btn-label");
submit.disabled = true;
spinner.hidden = false;
label.textContent = authMode === "register" ? "注册中…" : "登录中…";
try {
if (authMode === "register") {
await global.MobileSession.register(username, password);
@@ -287,10 +310,11 @@
}
replace(DEFAULT_HASH);
} catch (error) {
errorElement.textContent = error.message || "账号操作失败";
errorElement.hidden = false;
showAuthError(errorElement, error.message || "账号操作失败");
} finally {
submit.disabled = false;
spinner.hidden = true;
label.textContent = authMode === "register" ? "注册并进入" : "登录";
}
}
@@ -312,7 +336,7 @@
});
}
function render() {
function render(motion) {
const route = currentRoute();
if (route.name === "home") {
replace(DEFAULT_HASH);
@@ -331,6 +355,7 @@
else if (route.name === "feature") renderFeature(route.params.join("/"));
else if (route.name === "assistant") renderAssistant();
else if (route.name === "auth") renderAuth();
applyViewMotion(motion);
}
function bindGlobalEvents() {
@@ -359,10 +384,11 @@
const hash = currentHash();
if (stack.length > 1 && hash === stack[stack.length - 2]) {
stack.pop();
render("m-motion-pop-in");
} else if (hash !== stack[stack.length - 1]) {
stack.push(hash);
render("m-motion-push-in");
}
render();
});
}
@@ -377,7 +403,7 @@
} else {
stack.push(currentHash());
}
render();
render("m-motion-boot-in");
}
global.MobileRouter = {