提交 e355ce25 编写于 作者: X xjh22222228

feat: 足迹记忆

上级 8ce9afb2
......@@ -34,7 +34,7 @@
- [√] 三叉树分类、结构清晰、分类清晰。
- [√] 颜值与简约并存,不再是杀马特时代。
- [√] 支持3种浏览模式,创新。
- [√] 支持页面定位、滚动定位
- [√] 支持足迹记忆
- [√] 支持移动端浏览。
- [√] 支持搜索查询。
- [√] 纯静态, 提供自动化部署功能。
......@@ -91,7 +91,20 @@ npm run build
6、5分钟后打开 https://用户名.github.io/nav 就能看到一个非常强大的导航网站了。
注:如果想部署到自己的域名,那么以上教程同样适合,因为它提供了自动化部署, 之后可以通过 `CNAME``反向代理` 实现。
注:如果想部署到自己的域名,那么以上教程同样适合,因为它提供了自动化部署, 之后可以通过 `CNAME``反向代理` 实现:
```conf
# nginx
server {
listen 80;
server_name www.nav3.cn nav3.cn;
location / {
proxy_pass https://xjh22222228.github.io/nav/;
}
}
```
## 更新数据
......
......@@ -3,9 +3,9 @@ const DEFAULT_ICON = 'https://www.python.org/static/favicon.ico'
export default {
title: '依赖包',
icon: DEFAULT_ICON,
nav: [
{
icon: DEFAULT_ICON,
subtitle: 'HTTP/爬虫',
nav: [
{
......@@ -61,7 +61,6 @@ export default {
},
{
subtitle: '图像',
icon: DEFAULT_ICON,
nav: [
{
name: 'Pillow',
......@@ -77,13 +76,17 @@ export default {
},
{
subtitle: 'CLI',
icon: DEFAULT_ICON,
nav: [
{
name: 'Fire',
desc: 'Python Fire是一个用于从绝对任何Python对象自动生成命令行界面(CLI)的库。',
link: 'https://github.com/google/python-fire',
},
{
name: 'colorama',
desc: 'Python中简单的跨平台彩色终端文本',
link: 'https://pypi.org/project/colorama/',
},
]
}
]
......
media/poster.png

240.1 KB | W: | H:

media/poster.png

63.0 KB | W: | H:

media/poster.png
media/poster.png
media/poster.png
media/poster.png
  • 2-up
  • Swipe
  • Onion skin
import nav from '../../data'
import { Component } from '@angular/core'
import { Router, ActivatedRoute } from '@angular/router'
import { TONGJI_URL } from '../../config'
import { queryString, setLocation } from '../utils'
@Component({
selector: 'app-xiejiahe',
......@@ -9,24 +9,21 @@ import { TONGJI_URL } from '../../config'
styleUrls: ['./app.component.scss']
})
export class AppComponent {
nav: Array<any> = nav
constructor (private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
const hash = window.location.hash
const params = new URLSearchParams(hash.slice(hash.indexOf('?')))
const page = params.get('page')
const id = params.get('id')
const q = params.get('q')
const queryParams = { page, id, q }
this.goRoute(queryParams)
this.goRoute()
this.appendTongji()
this.activatedRoute.queryParams.subscribe(() => {
setLocation()
})
}
goRoute(queryParams: object) {
goRoute() {
const { page, id, q } = queryString()
const screenWidth = window.innerWidth
const queryParams = { page, id, q }
if (screenWidth < 768) {
this.router.navigate(['/app'], { queryParams })
......
interface ThreeProp {
name: string;
desc: string;
link: string;
language?: string[]
export interface INavFourProp {
icon?: string | null
name: string
desc: string
link: string
}
interface TwoProp {
subtitle?: string;
icon?: string | null;
nav: ThreeProp[]
export interface INavThreeProp {
subtitle?: string
icon?: string | null
showSideIcon?: boolean
collapsed?: boolean
nav: INavFourProp[]
}
export interface INavTwoProp {
title?: string
icon?: string | null
collapsed?: boolean
nav: INavThreeProp[]
}
export interface INavProps {
title: string;
icon?: string | null;
nav: TwoProp[]
title: string
id?: number
nav: INavTwoProp[]
}
import WEBSITE_LIST from '../../data'
import qs from 'qs'
import { BACKGROUND_LINEAR, ERROR_ICON } from '../../config'
import { INavProps } from '../types'
export function debounce(func, wait, immediate) {
let timeout
......@@ -29,7 +30,7 @@ export function randomInt(max: number) {
return Math.floor(Math.random() * max)
}
export function fuzzySearch(navList: any[], keyword: string) {
export function fuzzySearch(navList: INavProps[], keyword: string) {
let searchResultList = [{ nav: [] }]
function f(arr?: any[]) {
......@@ -115,6 +116,15 @@ export function queryString() {
let id = parseInt(parseQs.id) || 0
let page = parseInt(parseQs.page) || 0
if (parseQs.id === undefined && parseQs.page === undefined) {
try {
const location = window.localStorage.getItem('location')
if (location) {
return JSON.parse(location)
}
} catch {}
}
if (page > WEBSITE_LIST.length - 1) {
page = WEBSITE_LIST.length - 1;
id = 0;
......@@ -159,13 +169,13 @@ export function getWebsiteList() {
return webSiteList
}
export function setWebsiteList(v) {
if (!v) return
export function setWebsiteList(v?: INavProps[]) {
v = v || WEBSITE_LIST
window.localStorage.setItem('website', JSON.stringify(v))
}
export function toggleCollapseAll(websiteList?): boolean {
export function toggleCollapseAll(websiteList?: INavProps[]): boolean {
websiteList = websiteList || WEBSITE_LIST
const { page, id } = queryString()
......@@ -182,3 +192,12 @@ export function toggleCollapseAll(websiteList?): boolean {
return collapsed
}
export function setLocation() {
const { page, id } = queryString()
window.localStorage.setItem('location', JSON.stringify({
page,
id
}))
}
import nav from '../../../../data';
import { Component } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { APP_LANGUAGE } from '../../../../config';
import { onImgError, queryString } from '../../../utils';
import nav from '../../../../data'
import { Component } from '@angular/core'
import { Router, ActivatedRoute } from '@angular/router'
import { APP_LANGUAGE } from '../../../../config'
import { onImgError, queryString } from '../../../utils'
import { INavProps } from '../../../types'
@Component({
selector: 'app-home',
......@@ -12,18 +13,18 @@ import { onImgError, queryString } from '../../../utils';
export default class WebpComponent {
constructor (private router: Router, private activatedRoute: ActivatedRoute) {}
nav: Array<any> = nav;
id: number = 0;
page: number = 0;
open: boolean = false;
language: string[] = APP_LANGUAGE;
nav: INavProps[] = nav
id: number = 0
page: number = 0
open: boolean = false
language: string[] = APP_LANGUAGE
ngOnInit () {
this.activatedRoute.queryParams.subscribe(() => {
const { page, id } = queryString()
this.page = page
this.id = id
});
})
}
handleSidebarNav (index) {
......@@ -33,7 +34,7 @@ export default class WebpComponent {
page,
id: index,
}
});
})
}
handleCilckNav (index) {
......@@ -41,29 +42,29 @@ export default class WebpComponent {
queryParams: {
page: index,
}
});
})
this.open = !this.open;
(<any>window).$('.nav-open').slideUp(200);
(<any>window).$('.nav-open').slideUp(200)
}
handleToggleOpen() {
this.open = !this.open;
(<any>window).$('.nav-open').slideToggle(200);
(<any>window).$('.nav-open').slideToggle(200)
}
handleToWebsite(item, index, event) {
if (!Array.isArray(item.language)) {
window.open(item.link);
return;
window.open(item.link)
return
}
const el = (<any>window).$('.bottom-slide');
const $this = (<any>window).$(event.currentTarget);
const len = el.length;
const el = (<any>window).$('.bottom-slide')
const $this = (<any>window).$(event.currentTarget)
const len = el.length
for (let i = 0; i < len; i++) {
if (i === index) {
continue;
continue
}
el.eq(i).removeClass('active');
el.eq(i).removeClass('active')
}
$this.siblings('.bottom-slide').toggleClass('active')
}
......
......@@ -25,7 +25,7 @@
<nav class="top-nav user-select-none">
<a
*ngFor="let item of websiteList; let i = index;"
(click)="handleCilckNav(i)"
(click)="handleCilckTopNav(i)"
[class.active]="page === i"
class="ripple-btn">
{{ item.title }}
......@@ -50,7 +50,7 @@
</div>
</aside>
<div class="main" id="main" (scroll)="handleScroll($event)">
<div class="main">
<app-loading *ngIf="searchLoading"></app-loading>
<ul *ngIf="currentList.length && currentList[0].nav">
......@@ -92,7 +92,7 @@
/>
</div>
<div class="row" [class.hide]="item.collapsed">
<div class="row" *ngIf="item.collapsed">
<div class="click-btn" *ngFor="let el of item.nav">
<a [href]="el.link" target="_blank" rel="noopener noreferer">
<div class="top">
......
......@@ -295,10 +295,6 @@
transition: .1s ease-out;
overflow: hidden;
&.hide {
display: none;
}
a {
color: #333;
......
......@@ -2,6 +2,7 @@ import { Component } from '@angular/core'
import { Router, ActivatedRoute } from '@angular/router'
import { INDEX_LANGUAGE, GIT_REPO_URL } from '../../../../config'
import { annotate } from 'rough-notation'
import { INavProps, INavThreeProp } from '../../../types'
import {
debounce,
fuzzySearch,
......@@ -13,7 +14,7 @@ import {
toggleCollapseAll,
} from '../../../utils'
let equeue = []
let ANNOTATE_EQUEUE = []
@Component({
selector: 'app-home',
......@@ -24,8 +25,8 @@ export default class HomeComponent {
constructor (private router: Router, private activatedRoute: ActivatedRoute) {}
websiteList: any[] = getWebsiteList()
currentList: any[] = []
websiteList: INavProps[] = getWebsiteList()
currentList: INavThreeProp[] = []
id: number = 0
page: number = 0
searchKeyword: string = ''
......@@ -58,6 +59,8 @@ export default class HomeComponent {
if (tempPage !== page) {
this.setAnnotate()
}
setWebsiteList(this.websiteList)
})
this.handleSearch = debounce(() => {
......@@ -79,32 +82,30 @@ export default class HomeComponent {
}, 1000, false)
}
handleScroll(e) {
const target = e.target
const top = target.scrollTop;
(<any>window).sessionStorage.top = top
handleOnClickSearch() {
this.showInput = true
setTimeout(() => {
const searchEl = document.querySelector('.search') as HTMLInputElement
if (searchEl) {
searchEl.focus()
}
}, 0)
}
handleCilckNav(index) {
handleCilckTopNav(index) {
const id = this.websiteList[index].id || 0
this.router.navigate(['/index'], {
queryParams: {
page: index,
id,
_: Date.now()
}
})
}
handleOnClickSearch() {
this.showInput = true
setTimeout(() => {
try {
(<any>document).querySelector('.search').focus()
} catch (err) {}
}, 0)
}
handleSidebarNav (index) {
const { page } = queryString()
this.websiteList[page].id = index
this.router.navigate(['/index'], {
queryParams: {
page,
......@@ -122,17 +123,14 @@ export default class HomeComponent {
debug: false,
opacity: .2,
})
try {
document.getElementById('main').scrollTop = +(<any>window).sessionStorage.top || 0
} catch (e) {}
}
setAnnotate() {
const elList = document.querySelectorAll('.top-nav .ripple-btn') || []
if (elList.length === 0) return
equeue.forEach(item => item.hide())
equeue = []
ANNOTATE_EQUEUE.forEach(item => item.hide())
ANNOTATE_EQUEUE = []
const annotation = annotate(elList[this.page], {
type: 'underline',
......@@ -140,7 +138,7 @@ export default class HomeComponent {
padding: 3,
strokeWidth: 3
})
equeue.push(annotation)
ANNOTATE_EQUEUE.push(annotation)
annotation.show()
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册