blog's Introduction
blog's People
blog's Issues
npm 收集
- 权限问题
执行npm cache clean --force
, 如果报错是因为一个包引发,尝试单独安装此包之后再安装其他包。 - 版本号说明
x: 代表最新版
^1.0.1: 会安装1.x.x
~1.0.1: 会安装 1.0.x
*:安装最新版。
mac 设置chrome 跨域
终端执行命令:
open -n /Applications/Google\ Chrome.app/ --args --disable-web-security --user-data-dir=/Users/yourname/MyChromeDevUserData/
- yourname 为你的电脑名字
- MyChromeDevUserData 为当前跨域浏览器存放备份的 文件夹
参考: https://www.cnblogs.com/laden666666/p/5544572.html
记录 ssr 遇到的问题
-
产生白屏的原因
网站加载一个 html 模版页面,使用打包后的 js 生成对应的 html 标签,在这个过程中,js 加载的网络时间,js 生成 dom 的时间段页面都是白屏
-
无法找到静态资源文件。
在我们创建的 node server 中需要加入静态资源的路由识别。例如
const uri = url.parse(req.url).pathname; if (uri === '/') { // 首页 渲染 html页面 res.end(serverData); } else { //输出打包后的静态文件 index.js fs.createReadStream('./server/build/index.js').pipe(res); }
tips: 默认为 package.json 所在目录作为根路径
-
require is not defined
- 原因: 出现这种问题一般是 因为 服务端打包的文件规范为 commonjs, 会输出类似
module.exports = require(\"fs\");
的代码,在浏览器端无法识别。 - 解决方案: 在启动 server 时;server 端打包 react 文件通过
renderToString
能获取到 html 结构;同时 client 端打包ReactDOM.hydrate
;在 server 端返回的 html 结构内引用 client 端打包的 js,对 html 结构进行事件绑定。
- 原因: 出现这种问题一般是 因为 服务端打包的文件规范为 commonjs, 会输出类似
-
如何处理数据
- server 端可以用 getInitialProps (getStaticProps/getServerSideProps)方法获取异步数据,然后渲染到组件上,然后再通过 renderTotring 方法转换为 html结构
- getInitialProps 只有在 page上才有此方法,目前猜测是因为后端路由的关系,一个路由对应一个页面,但是这个页面里面有多少组件这是未知的
- client 端可以通过 useEffects 方法获取异步数据
TODO:待手动实现 getInitialProps
- server 端可以用 getInitialProps (getStaticProps/getServerSideProps)方法获取异步数据,然后渲染到组件上,然后再通过 renderTotring 方法转换为 html结构
-
document is not defined
根本原因:
style-loader
会将css打入js中,在js中生成style标签,使用document.createElement("style”)
; 然而服务端没有document
这个api。
使用mini-css-extract-plugin
插件将css代码从 js文件中抽离出来,
不要在服务端打包的js中使用document
; -
如何理解 getServerSideProps (getInitialProps)
-
async await
- async 标志了当前函数的返回值为一个promise 对象;
- await 等待一个表达式,如果是 函数hello 内部返回了一个promise对象,则 await阻塞接下来的代码执行。
- async 默认会返回一个promise 对象。
并没有输出 a 和end. 因为被阻塞了。
async function hello() { console.log('hello'); const a = await fetch('https://www.baidu.com'); console.log('a: ', a) console.log('end.') } hello() // hello (console.log输出) // Promise {<pending>} (如果没有返回值,async 函数默认会返回一个promise对象)
const b = async () => { return 1 + 1; // no // console.log('b'); no // return fetch('https://www.baidu.com'); yes } async function hello2() { console.log('hello'); const a = await b; console.log('a: ', a) console.log('end.') } hello2() // hello // a: 2 // end. // Promise {<pending>} (如果没有返回值,async 函数默认会返回一个promise对象) /// await 这里不会阻塞后续表达式执行,因为 await后面不是一个promise对象
-
前端模块化
https://juejin.cn/post/6844903744518389768#heading-50
https://es6.ruanyifeng.com/#docs/module
https://es6.ruanyifeng.com/#docs/module-loader
iife 模块
-
iife (Immediately-Invoked Function Expression)立即执行函数 | 匿名函数自调用 (闭包)
- 作用:数据是私有的,外部只能调用暴露的方法
- 如下所示,
iife_2.js
依赖iife_1.js
// case 1 (function (window) { // 外部 let prefix = 'https://www.bing.com'; function innerCalc(query) { // 内部处理函数,外部无法访问 return prefix + query; } function foo(query) { // 暴露给外部的方法 console.log(`foo() ${prefix}`); return innerCalc(query); } // 暴露方法 return (window.myModule = { foo }); })(window);
// case 2 (function (module) { // 依赖外部的 module function bar() { const data = module.foo('?q=123'); return `${data}&form=safari`; } module.bar = bar; })(myModule);
// html 中 <script type="text/javascript" src="/src/modules/iife_1.js"></script> <script type="text/javascript" src="/src/modules/iife_2.js"></script> <script type="text/javascript"> console.log(myModule.bar()); </script>
- 导致的问题
- 请求过多: 我们要依赖多个iife 模块,那就会有发送多个请求。
- 依赖容易模糊:我们必须知道准确的依赖顺序,否则页面就会报错。
CommonJS
-
概述
- Nodejs 的模块规范,每个文件就是一个模块
- 服务端:模块的加载是运行时同步加载
- 浏览器端:浏览器不支持 commonjs 规范, commonjs 模块需要再浏览器端使用,需要提前编译打包。
-
语法
-
暴露模块:
module.exports = value
exports.xxx = value
-
引入模块:
require(xxx)
xxx 可以是文件路径,也可以是第三方 commonjs 包名require
命令用于导出一个模块文件中的exports
对象
-
-
特点
-
commonjs 模块 也可用
.cjs
结尾 -
commonjs 模块在被
require
时,导出的对象是原始模块的值的一份拷贝。let count = 1; function addCount() { count++; return count; } exports.count = count; exports.addCount = addCount; // 外部模块执行 addCount 之后,导出的count 仍然为 1
-
浏览器端如何使用?
-
如果在浏览器端直接引入 commonjs 模块,页面会报错
require is not defined
。 因为浏览器端没有 require,module, module.exports 这三个对象。 -
使用
browserify
这个库让浏览器可以支持 commonjs 模块 , 它会将所有模块 放入一个数组,当执行 require('xx') 时,就加载 xxx 对应 id 的 source文件,并返回 exports 对象。[ { id: 1, source: "const data = require('./commonjs_1');\r\n\r\nfunction log() {\r\n console.log(data.count);\r\n console.log(data.addCount());\r\n}\r\n\r\nlog();\r\n\r\nsetTimeout(log, 100);", deps: { './commonjs_1': 2 }, entry: true }, { id: 2, source: 'let count = 1;\r\n\r\nfunction addCount() {\r\n count++;\r\n return count;\r\n}\r\n\r\nexports.count = count;\r\nexports.addCount = addCount;', deps: {} } ];
-
-
-
commonjs 的问题
- 无法异步加载文件
- 一个文件只会导出一个 exports 对象,无法静态分析,意味着无法做 tree-shaking
-
总结
- commonjs 规范比较适用服务器端开发,因为一般 node 应用依赖的模块都会先被存在本地磁盘中,所以同步加载的模式比较块,不需要使用异步模式。
- 但是浏览器环境就不一样了,页面依赖的文件很多来自服务端,需要异步加载处理。所以 commonjs 在浏览器环境不是很适用。
ES module
https://es6.ruanyifeng.com/#docs/module
-
概述
-
ES6 模块的设计**是尽量的静态化,使得编译时就能确定模块的依赖关系,这样有很多好处,比如 tree-shaking
-
判断当前代码是否在 es6 模块中
if (this === undefined)
-
-
语法
-
模块导出
export const name = 'Tom'; export let age = 1; export var address = 'Cheng Du'; export function sayHi(name){ console.log(`hi ${name}`)} export default function App(){ return 'App' } // 默认导出 export { name, sayHi, App } export { name as Name } // 使用 as 重命名 export { name as default } // name 作为 default 导出 // 特殊用法 export { default as AppIndex } from './es6_0'; export * from './es6_0'; // 表示在当前文件中再导出 es6_0.js 文件中的所有模块
-
-
模块引入
import { firstName, lastName, year } from './index.js'; import { firstName as name } from './index.js'; import { default as Index } from './index.js'; import * as all from './index.js'
-
import 异步加载模块
import('./es6_0.js').then(() => {})
-
es6 模块的加载规则
https://es6.ruanyifeng.com/#docs/module-loader
- script 脚本异步访问 js
async
文件一旦下载完,浏览器会优先执行此脚本。暂停执行其他任务defer
文件一旦下载完,会等待页面渲染完之后再执行,触发 domcontentloaded 事件
- script 脚本访问 es6 模块
type = "module"
=== 支持esmodule
并且添加了defer
属性
- script 脚本异步访问 js
Nodejs 的实际使用
https://es6.ruanyifeng.com/#docs/module-loader#Node-js-的模块加载方法
-
commonjs
- .cjs 结尾的文件以 commonjs 规范解析。.cjs 结尾的文件只能用 commonjs 规范。
- package.json 中 type 默认为 commonjs,表示当前项目中以js 结尾的文件以 commonjs 规范执行
-
esmodule
- .mjs 结尾的文件以 esmodule 规范解析。.mjs 结尾的文件只能用 esmodule 规范。
- 设置 package.json 中 type ="module"时,
package.json
-
type 属性 不同的值对应了什么意思
commonjs
当前项目中以js 结尾的文件以 commonjs 规范执行 。 默认module
当前项目中以 js 结尾的文件以 esmodule规范执行。
type: 'module' | 'commonjs'
-
main 字段
- main 指定了模块的入口文件, 与type字段配合使用
当前暴露的项目为 es module,入口为 dist/index.js
// 包: es-test-module type: 'module', main: './dist/index.js' // 会被转换为 nod_modules/es-test-module/dist/index.js
-
exports 字段
-
exports
字段的优先级高于main
字段exports 字段可以为 多个目录设置别名
// 包名: es-test-modules type: 'module', exports: { submodule: "./dist/submodule/" } // 如果执行 import subFunc from 'es-test-modules/submodule/xxxx.js' // 会被转换为 import subFunc from 'node_modules/es-test-modules/dist/submodule/xxx.js'
-
exports
这种写法与main
一致,但是优先级高于main
exports: { ".": "./dist/index.js" }
-
exports
这种写法只有支持 es6 语法的 nodejs 才认识,所以可以配合main
一起,兼容旧版本和新版本的 nodejsmain: './dist/index.js' exports: { ".": "./dist/index.js" }
-
-
commonjs 模块 与 es6 模块 互相引用
-
https://es6.ruanyifeng.com/#docs/module-loader#ES6-模块加载-CommonJS-模块
-
使用 commonjs 模式无法加载 es6 模块的文件 ,因为 commonjs 是同步加载,es6 模块内部可以使用 await 关键字
(async () => { await import('./my-app.mjs'); })();
-
es6 模式可以加载 commonjs 模块的文件
// 方式一 import name from 'commonjs-package' // 方式二 es6 模块中混用 commonjs 模块 import { createRequire } from 'module'; const require = createRequire(import.meta.url); const name = require('commonjs-package');
-
总结
现在是 2021 年了,编写 Node 程序时应该尽量使用 esmodule 模块规则来开发,esmodule 可以较好的兼容 commonjs 模块,反之则不行。
- iife
- 使用一个立即执行函数维持模块之间的关系,并使用闭包隐藏内部变量,这种方式到今天也仍然在使用。
- 缺点是在模块太多时很容易出现依赖顺序问题。并且无法静态分析。
- commonjs
- Node 沿用至今的 模块处理方案,通过导出
exports
对象, 再使用require(xxx)
方法导入实现。它与 esmodule 模块最大的不同有两点- 无法异步加载文件, 意味着
require('https://xxxxx,js')
是不行的。 require
的值是exports
导出的值的 复制。
- 无法异步加载文件, 意味着
- commonjs 模块无法兼容 es module 模块
- Node 沿用至今的 模块处理方案,通过导出
- es module
- es6 出现的模块管理方案,Node 13.2 开始支持,通过
export
导出模块,import
引入模块实现. - 它与 commonjs 不同的是
import
语法可以异步加载文件,import('xx.js').then()
import
导出的值是export
的值的引用
- es6 出现的模块管理方案,Node 13.2 开始支持,通过
实现一个 Promise
Promise 解决了哪些问题
- 回调地狱常见于 Nodejs 的 Api
fs.readFile
fs.writeFile
- 提供了常用的 并发模式 Api
Promise.all
Promise 对象的主要特点
-
状态
- pending, Promise 对象的初始状态
- fulfilled, Promise 对象 操作成功的状态
- rejected, Promise 对象 操作失败的状态
-
then
- 返回一个新的 Promise 对象
- 可以链式调用
- 值穿透特性
- then 方法内返回新的的 Promise 对象
// 返回 Promise, 可以链式调用then new Promise().then().then();
// 值穿透 new Promise((resolve, reject) => { resolve(1); }) .then() .then((data) => { console.log(data); // 1 });
编写 Promise 的步骤
-
实现同步的 Promise
class Promise { constructor(executor) { this.status = 'pending'; this.value = undefined; this.reason = undefined; let resolve = (value) => { if (this.status === 'pending') { this.status = 'fulfilled'; this.value = value; } } let reject = (value) => { if (this.status === 'pending') { this.status = 'rejected'; this.reason = value; } } try { executor(resolve, reject) } catch ((e) => { reject(e) }) } then = (onFulfilled, onRejected) => { if (this.status === 'fulfilled') { let x = onFulfilled(this.value); return x; } if (this.status === 'rejected') { let x = onFulfilled(this.value); return x; } if (this.status === 'pending') { // 异步 } } }
-
支持异步
-
暂存 onFulfilled/onRejected 函数
const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; const PENDING = 'pending'; /** - 状态 pending|fulfilled|rejected - resolve/reject - then */ class Promise { status: string; value: any; // resolve return reason: any; // reject return onResolveCallbacks: any; // 暂存异步之后需要执行的动作 onRejectCallbacks: any; constructor(executor: any) { this.status = PENDING; this.value = null; this.onResolveCallbacks = []; this.onRejectCallbacks = []; let resolve = (value: any) => { if (this.status === PENDING) { this.status = FULFILLED; this.value = value; this.onResolveCallbacks.forEach((fn: any) => fn(this.value)); } }; let reject = (reason: any) => { if (this.status === PENDING) { this.status = FULFILLED; this.value = reason; this.onRejectCallbacks.forEach((fn: any) => fn(this.value)); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } then = (onFulfilled?: any, onRejected?: any) => { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (y: any) => y; onRejected = typeof onRejected === 'function' ? onRejected : (y: any) => y; if (this.status === FULFILLED) { let x = onFulfilled(this.value); return x; } if (this.status === REJECTED) { let x = onRejected(this.reason); return x; } if (this.status === PENDING) { this.onResolveCallbacks.push(() => { onFulfilled(this.value); }); this.onResolveCallbacks.push(() => { onRejected(this.reason); }); } }; }
-
-
then 支持链式调用
-
每个 then 方法都返回 promise 对象
-
只需要改造 then 方法
then = (onFulfilled?: any, onRejected?: any) => { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (y: any) => y; onRejected = typeof onRejected === 'function' ? onRejected : () => { throw new Error('Uncaught'); }; if (this.status === FULFILLED) { return new Promise((resolve: any, reject: any) => { try { let x = onFulfilled(this.value); resolve(x); } catch (error) { reject(error); } }); } if (this.status === REJECTED) { return new Promise((resolve: any, reject: any) => { try { let x = onRejected(this.reason); resolve(x); } catch (error) { reject(error); } }); } if (this.status === PENDING) { return new Promise((resolve: any, reject: any) => { try { this.onResolveCallbacks.push(() => { try { let x = onFulfilled(this.value); resolve(x); } catch (error) { reject(error); } }); this.onRejectCallbacks.push(() => { try { let x = onRejected(this.reason); resolve(x); } catch (error) { reject(error); } }); } catch (error) { reject(error); } }); } };
-
-
then 方法支持内部返回 promise
-
即是
onFulfilled
onRejected
方法返回 Promise -
内部返回的 promise 执行之后,再继续执行外部
then
方法 - 这里将 then 的返回值抽出来,用一个函数包装内部逻辑
let x = onFulfilled(this.value); // 如果 x 返回 promise 对象 let resolvePromise = (promise, x, resolve, reject) => { // 判断x 是否是 promsie try { if ( typeof x !== null && (typeof x === 'function' || typeof x === 'object') ) { let then = x.then; if (typeof then === 'function') { then.call( promise, (value) => { // resolve(x) // 如果 then 仍然是一个promise resolvePromise(promise, value, resolve, reject); }, (e) => { reject(e); } ); } } else { return resolve(x); } } catch (e) { reject(e); } };
-
Git 收集
-
修改 commit 信息,使用命令
git commit --amend
, vi 修改, 只修改最后一条commit 信息。git 撤消 -
修改 commit 信息 (记录 已push), 使用命令
git rebase -i head~5
。 -
取消
git commit
记录,但是保留代码:git reset --soft head~1
, 1 表示commit 条数。 -
取消
git commit
记录, 不保留代码: ` git reset --hard commitId ```。 -
window 下设置 git 大小写敏感
git config core.ignorecase false
。 -
删除已经被放入 git 历史版本的文件或文件夹
git rm --cached plugins/index.js
git commit -m "chore: remove a file in git history"
-
合并commit 记录(只能合并相邻的commits)
git rebase -i hash值
, 然后将pick 选为 squash.
squash 会将当前commit 合并到上一个commit。
保存退出(wq)之后,回提示你是否需要更新commit 信息
tips: 如果遇到合并冲突, 先解决冲突,然后git add 之后执行 git rebase --continue -
更新 commit的用户名和地址
如果已经commit了, 可以直接执行git commit --amend --author="dbwcooper <[email protected]>"
如果未commit
git config --local user.name "dbwcooper"
git config --local user.email "[email protected]"
div 如何自适应高度
背景: 左右布局的div 块,左侧为菜单栏,右侧为内容块,如何保证左右块同高?
如何理解 react 服务端渲染
#coding
Web页面 文件下载
文件下载
常见处理文件下载方式有两种
-
新开浏览器tab下载
后端返回格式 如何处理 优点 缺点 文件流 window.open 简单 新开tab页面会有一瞬间的空白;ie下可能拦截; 无法处理接口异常; 文件链接 window.open 简单 新开tab页面会有一瞬间的空白;ie下可能拦截; 无法处理接口异常; -
当前页面下载
后端返回格式 如何处理 优点 缺点 文件流 iframe 能处理接口异常;有浏览器自带的进度条显示 交互友好 无 文件链接 iframe 能处理接口异常;有浏览器自带的进度条显示 交互友好 无 文件流 a 简单,ie 不兼容 无 文件链接 a 简单,ie 不兼容 无 -
使用 a 标签
- 要求
- api 请求方式为 get, 并返回文件流 | 或一个具体的文件
- api 的地址与当前页面的地址的 域名 必须一致! (跨域)
- api 地址必须以 https 开头 见 MDN 安全策略
- 要求
-
缺点
- 无法得知下载文件的进度
- ie下 a 标签没有 download 属性,点击a 标签会直接打开文件 而不是下载。
-
代码
const A_ID = 'd_a_key_2020'; const getADownload = (blob: Blob | string, fileName: string) => { const url = typeof blob === 'string' ? blob : window.URL.createObjectURL(blob); let aDom = document.getElementById(A_ID) as HTMLAnchorElement; if (!aDom) { aDom = document.createElement('a'); document.body.appendChild(aDom); } aDom.id = A_ID; aDom.style.display = 'none'; aDom.href = url; aDom.download = fileName; // ie dont work, download 属性添加之后,点击a 标签不会直接打开文件,而是下载这个文件。 aDom.click(); aDom.onload = () => { console.log('onload:') } };
-
使用 iframe 标签 (最靠谱)
-
要求
- api 请求方式为 get, 并返回文件流
- api 的地址与当前页面的地址的 域名 必须一致! (跨域)
- api 地址必须以 https 开头 见 MDN 安全策略
- api 不是具体的文件名
ok: https://xxxx/report-file/e455e9ef-74f6-4540-8184-3c2f76224f67
error: https://xxxx/report-file/logo.xlsx
-
代码
const getIframeDownload = (api: string, onComplete?: (str: string | null) => void) => { let iframeDom = document.getElementById(IFRAME_ID) as HTMLIFrameElement; if (iframeDom) { document.body.removeChild(iframeDom); } iframeDom = document.createElement('iframe'); iframeDom.style.display = 'none'; iframeDom.id = IFRAME_ID; iframeDom.src = api; // trigger download; iframeDom.onload = () => { // iframe 的地址与 当前页面的地址必须在相同的域名下! 才能拿到 contentDocument const iframeDoc = iframeDom.contentDocument; if (iframeDoc) { if ( iframeDoc.readyState === 'complete' || iframeDoc.readyState === 'interactive' ) { // 文件下载出错时;后端会返回一串字符,一般是一串json, 此时responseText有值 // 文件正常下载时; responseText === null if (typeof onComplete === 'function') { const responseText = iframeDoc.body.textContent || null ; onComplete(responseText) } } } }; document.body.appendChild(iframeDom); };
-
-
POST 方式下载
代码
// saveAs, 建议使用 https://github.com/eligrey/FileSaver.js/ export function downloadUrlFile(url: string) { const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'blob'; // xhr.setRequestHeader('Authorization', 'Basic a2VybWl0Omtlcm1pdA=='); xhr.onload = () => { if (xhr.status === 200) { // 获取图片blob数据并保存 // saveAs(xhr.response, 'abc.xlsx'); } }; xhr.send(); }
光标快捷操作
mac终端的光标操作
删除快捷键
删除 光标前的命令
control + h
=== backspace 回退键control + w
删除光标前的一个单词- 例如执行git操作写错了 status, git stsau 使用
control + w
可以快速删除 ststau - 简单说: git ststau -> git
- 例如执行git操作写错了 status, git stsau 使用
control + u
删除光标之前到行首 的所有字符串- git ststau -> 空白
删除 光标后的命令
control + k
删除光标后的 所有字符
删除 的其他命令
control + l
清屏 相当于输入clear
光标移动
control + a
光标向左移动一位control + e
光标向右移动一位option + <
光标 单词间移动 向左option + >
光标 单词间移动 向右option + shift + \
光标在 {} 上下移动command + up/down
光标移动到文件头/文件尾
vscode 光标操作
https://geek-docs.com/vscode/vscode-tutorials/vscode-keyboard.html#i
-
option + command + .
格式化单行代码 -
control + `
打开vscode 的terminal -
在word 上加特殊符号
control + command + 空格
左上角 设置 -> 项目符号 + 星星 -> 拖动符号✅到pages 文档内
删除
command + shift + k
删除选中行
编辑
command + enter
在光标所在行的下一行新增一行command + shift + enter
在光标所在行的上一行新增一行
撤销 光标移动
command + u
合并代码行
ctrl + j
合并两行代码为一行代码
关闭当前窗口内打开的所有 tab
command + k + w
获取元素距离位置
问题
- 使用 getBoundingClientRect 获取元素位置时,top 和 left 值 获取不准确。
场景
- 切换页面A -> 页面B,不刷新页面只重新挂载同一组件。
- 在
componentDidMount
内使用getBoundingClientRect
获取元素相对文档的x y轴坐标
如何重现
- 页面 A 滑动滚动条,使得
window.scrollY
不为0 ;(最好滑动滚动条到页面底部)。 - 此时切换页面B,页面不刷新,但是滚动条会默认滑动到页面顶部。
- 在组件的
componentDidMount
内使用getBoundingClientRect
方法获取到的height
top
; 此时的height
top
不是相对于页面B的文档,而是相对于页面A文档的最后状态。
解决方案
- 在组件重新挂载时,强制将滚动条滚动到页面顶部。
import React from 'react';
const scrollToTop = () => {
const sTop =
document.documentElement.scrollTop ||
document.body.scrollTop ||
document.scrollingElement!.scrollTop;
if (sTop > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, sTop - sTop / 8);
}
};
class App extends React.Component<
{},
{
headerTop: number;
top: number;
}
> {
state = {
headerTop: 0,
top: 0,
};
siderRef = React.createRef<HTMLDivElement>();
constructor(props) {
super(props);
scrollToTop();
}
componentDidMount() {
this.setHeaderTop();
document.addEventListener('scroll', () => {
const { headerTop } = this.state;
// const { height } = this.siderRef.current!.getBoundingClientRect();
// const {
// height: titleHeight,
// } = this.siderRef
// .current!.getElementsByClassName('stellr-dashboard-sider-title')[0]
// .getBoundingClientRect();
// const {
// height: menuHeight,
// } = this.siderRef
// .current!.getElementsByClassName('stellr-dashboard-menu')[0]
// .getBoundingClientRect();
// 找到 最大滚动距离
const maxScrollTop = 300;
// 找到已经滚动的高度
const tempTop =
window.scrollY - headerTop > 0 ? window.scrollY - headerTop : 0;
// 计算 menu 和 title在sider 内应该滑动的距离
const newTop = tempTop > maxScrollTop ? maxScrollTop : tempTop;
window.requestAnimationFrame(() => {
this.setState({ top: newTop });
});
});
}
componentWillUnmount() {
document.removeEventListener('scroll', () => {});
}
setHeaderTop = () => {
if (this.siderRef && this.siderRef.current) {
// 在滚动条滚动时, top 和 left 的值会根据滚动条的变化而变化。
// 如果页面不刷新 页面A -> 页面 B; 重新挂载此组件,getBoundingClientRect第一次获取到的 top, left 值会受滚动条的影响。
// 使用 offsetTop可替换
const { top } = this.siderRef.current!.getBoundingClientRect();
this.setState({
headerTop: top, // 当前div的左上角距离整个 文档的高度
// siderHeight: 0,
});
}
};
render() {
const { top } = this.state;
return (
<div
style={{ height: '100%', display: 'flex', flex: 1 }}
ref={this.siderRef}
>
<div style={{ position: 'absolute', left: 0, top, width: '100%' }}>
滚动块
</div>
</div>
);
}
}
export default App;
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.