学习获得成就感
学习中获得成就感非常重要的!将会决定选择的路线能否持之以恒的坚持下去👇🏻
suggestion by Ai
- 设定明确的目标:设定具体、可量化的学习目标,这样你在完成每个目标时都能够感到满足和有成就感。
- 分解大目标:如果你的学习目标很庞大,可以将其分解成更小、更具体的任务。完成每个小任务都是一个里程碑,让你感到进步和成就。
- 庆祝里程碑:每当达到一个重要的学习里程碑,不要忘记给自己一些小奖励或庆祝的方式,这会增强你的成就感和动力。
- 记录进步:保持一个学习日记或记录表,记录你的学习进展和成就。回顾过去的进步,会让你更有动力和自豪感。
- 寻求反馈:寻求他人的反馈和认可,他们的鼓励和肯定会增强你的成就感。可以向老师、同学、朋友或家人请教并分享你的学习成果。
- 持续学习:保持对学习的热情和好奇心,持续进步和学习新知识会带来更多的成就感。
💪💫 记住,学习的过程需要时间和努力,不要忘记欣赏自己的进步,享受学习的乐趣!加油!
为什么写这篇文章
- 用惯了封装好的库(时代发展不可避免),做技术需要探究下原理和实践过程。
- 记录下学习的内容
- 复盘 + 总结
作用
可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。
location.hash
🤔 location.hash 是一个包含在网页 URL 中的片段标识符,通常以 "#" 开头。它用于在网页中指示特定位置或锚点,让浏览器可以直接跳转到对应的片段或元素。
具体来说,当 URL 中包含了 "#" 字符后面的部分,浏览器就会将这部分信息解析为 location.hash。这使得网页作者可以通过设置特定的锚点,使用户在访问网页时直接跳转到指定的位置。这对于长页面或包含目录导航的文档特别有用。
表现形式:http://127.0.0.1:8080/index.html#index
涉及api
location.hash、onhashchange
- 设置location.hash
- onhashchange 监听hash的变化,做其他处理
javascript
location.hash = '/path';
document.addEventListener('hashchange',function(e){
// ...
},false)
实现过程
父类
抽象因为history路由同样需要这些方法。父类,主要存储历史记录、路由表、当前路由、组件渲染
javascript
class Parent {
constructor(config) {
this._routes = config.routes;
this.routeHistory = [];
this.currentUrl = '';
this.currentIndex = -1;
}
// 路由变化触发
getRoute = () => {
const routes = this._routes;
const route = routes.find((r) => r.path === this.currentUrl);
this.renderComponent(route);
};
// 渲染路由组件
renderComponent = (route) => {
const component = route.component;
if (typeof component === 'function') {
console.log('renderComponent');
component();
}
};
}
export default Parent;
Hash
子类实现hash初始化、hash监听、跳转方法
javascript
import Parent from './Parent.js';
class Hash extends Parent {
constructor(config) {
super(config);
this.init();
}
// 注册hashchange、初始化默认加载路由
init(){}
// 事件处理函数
refresh(){}
// 地址栏添加#/path,加载默认路由组件
initLocationHash(){}
// 改变location.hash =path;
changeLocatinHash(path){}
push(path){}
go(index){}
back(){}
forward(){}
}
export default Hash;
具体实现
初始化
javascript
class Hash extends Parent{
init(){
this.initLocationHash();
window.addEventListener('hashchange', this.refresh.bind(this), false);
window.addEventListener('load', this.refresh.bind(this), false);
}
// 路由变化触发函数
refresh(e) {
this.getRoute();
}
initLocationHash = () => {
// 如果currentUrl为空表示初始状态
if (!this.currentUrl) {
// 找到index为true的路由并渲染
let defaultItem = this._routes.find((r) => r.index);
this.currentUrl = defaultItem.path;
this.currentIndex = 0;
this.routeHistory = [defaultItem];
this.changeLocationHash(this.currentUrl);
this.getRoute();
}
};
}
改变路由的方法
javascript
class Hash extends Parent{
go = (index = 1) => {
if (index > 0) {
this.currentIndex += index;
} else {
(this.currentIndex -= index) < 0 && (this.currentIndex = 0);
}
const route = this.routeHistory[this.currentIndex];
console.log(route, 'route history');
this.changeLocationHash(route?.path);
return route;
};
push = (path) => {
const route = this._routes.find((r) => r.path === path);
this.routeHistory.push(route);
this.currentIndex = this.routeHistory.length;
this.changeLocationHash(route.path);
return route;
};
back = () => {
this.go(-1);
};
forward = () => {
this.go();
};
}
消费
创建路由表并注册,导出history消费。
javascript
import HashRouter from './packages/Router/Hash.js';
import AboutMe from './modelControl/AboutMe/index.js';
import Article from './modelControl/article/index.js';
const routes = [
{ index: true, path: '/index', index: true, component: AboutMe },
{ path: '/about', component: AboutMe },
{ path: '/article', component: Article },
];
const history = new HashRouter({ routes });
export default history;
模块中调用
javascript
querySelectorAll('[data-menu]').forEach((menu) => {
menu.onclick = () => {
history.push(path);
};
});
react-route的 Link
主要是对a标签进行拦截阻止默认行为,进行路由处理。根据对比location.origin是否为外部链接判断,否则认为是内容路由跳转
typescript
export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
function LinkWithRef(
{
onClick,
relative,
reloadDocument,
replace,
state,
target,
to,
preventScrollReset,
...rest
},
ref
) {
// ...其他实现
// 执行路由方法
let internalOnClick = useLinkClickHandler(to, {
replace,
state,
target,
preventScrollReset,
relative,
});
function handleClick(
event: React.MouseEvent<HTMLAnchorElement, MouseEvent>
) {
//响应自定义click事件
if (onClick) onClick(event);
if (!event.defaultPrevented) {
// 执行路由行为
internalOnClick(event);
}
}
return (
// eslint-disable-next-line jsx-a11y/anchor-has-content
<a
{...rest}
href={absoluteHref || href}
onClick={isExternal || reloadDocument ? onClick : handleClick}
ref={ref}
target={target}
/>
);
})
效果
结束
- 掌握hash路由实现原理
- 提高自己封装能力
- 探究现有封装库(react-router),学习源码思路
- 对自己来说还是很有意思的