全局 Git 钩子整体设置流程
一、目标与行为摘要
- 在 /Your/work/dir 及其子目录下的 Git 仓库中,执行 git commit 时,若未设置 NO_XXX,则在提交说明第一行末尾自动追加 [xxx]。
- 不在上述路径下的仓库:不追加;仍会尝试执行该仓库 [……]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
export type INDEXEDDB_PARAMS = { db_name: string; // 数据库名称 store_name: string; // 仓库名 version?: number; // 版本 data?: any; // 存储数据 }; class IDB { protected db: IDBDatabase | null; constructor() { this.db = null; this.open = this.open.bind(this); this.put = this.put.bind(this); this.get = this.get.bind(this); this.getAll = this.getAll.bind(this); this.delete = this.delete.bind(this); } // 开 open({ db_name, store_name, version }: INDEXEDDB_PARAMS) { return new Promise((resolve, reject) => { const indexedDB = (window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB); const DB = indexedDB?.open(db_name, version); DB.onerror = (event) => { const target = event?.target as IDBRequest; console.log(`IndexedDB ${db_name} 打开失败:${target?.error?.name}`); reject(target?.error); }; DB.onsuccess = (event) => { console.log(`IndexedDB ${db_name} 打开成功`); const target = event?.target as IDBRequest; this.db = target?.result; resolve(this.db); }; DB.onupgradeneeded = (event) => { console.log(`IndexedDB ${db_name} onupgradeneeded`); const target = event?.target as IDBRequest; const _db = target?.result; if (!_db?.objectStoreNames?.contains(store_name)) { _db.createObjectStore(store_name, { autoIncrement: true, }); } }; }); } // 有则覆盖,无则新增 put({ store_name, data }: INDEXEDDB_PARAMS) { return new Promise((resolve, reject) => { const transaction = this?.db?.transaction([store_name], "readwrite"); const objectStore = transaction?.objectStore(store_name); const request = objectStore?.put(data); if (request) { request.onsuccess = () => { console.log("数据写入成功"); resolve("数据写入成功"); }; request.onerror = (event) => { const target = event?.target as IDBRequest; console.log("数据写入失败:", target?.error?.name); reject(target?.error); }; } else { reject("put error"); } }); } // 取 get({ store_name, key, }: INDEXEDDB_PARAMS & { key: IDBValidKey | IDBKeyRange }) { return new Promise((resolve, reject) => { const transaction = this?.db?.transaction([store_name], "readonly"); const objectStore = transaction?.objectStore(store_name); const request = objectStore?.get(key); if (request) { request.onsuccess = (event) => { const target = event?.target as IDBRequest; resolve(target?.result); }; request.onerror = (event) => { const target = event?.target as IDBRequest; console.log( `${store_name} 获取数据 ${key} 失败:`, target?.error?.name ); reject(target?.error); }; } else { reject("get error"); } }); } // 全取 getAll({ store_name }: INDEXEDDB_PARAMS) { return new Promise((resolve, reject) => { const transaction = this?.db?.transaction([store_name], "readonly"); const objectStore = transaction?.objectStore(store_name); const request = objectStore?.getAll(); if (request) { request.onsuccess = (event) => { const target = event?.target as IDBRequest; resolve(target?.result); }; request.onerror = (event) => { const target = event?.target as IDBRequest; console.log(`${store_name} 获取所有数据失败:`, target?.error?.name); reject(target?.error); }; } else { reject("get all error"); } }); } // 删 delete({ store_name, key, }: INDEXEDDB_PARAMS & { key: IDBValidKey | IDBKeyRange }) { return new Promise((resolve, reject) => { const transaction = this?.db?.transaction([store_name], "readwrite"); const objectStore = transaction?.objectStore(store_name); const request = objectStore?.delete(key); if (request) { request.onsuccess = () => { console.log("数据删除成功"); resolve("数据删除成功"); }; request.onerror = (event) => { const target = event?.target as IDBRequest; console.log("数据删除失败:", target?.error?.name); reject(target?.error); }; } else { reject("delete error"); } }); } } export default new IDB(); |
使用开源库:html2canvas
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>H5滚动截长图示例</title> <script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script> <style> body { font-family: 'Arial', sans-serif; margin: 0; padding: 20px; background-color: #f5f7fa; } .container { max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } h1 { color: #333; text-align: center; } .controls { display: flex; justify-content: center; gap: 10px; margin: 20px 0; } button { padding: 10px 20px; background: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; transition: background 0.3s; } button:hover { background: #45a049; } #result { margin-top: 20px; text-align: center; } #content { margin-top: 30px; padding: 20px; background: #f9f9f9; border-radius: 5px; } .section { margin-bottom: 30px; padding: 15px; background: white; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .loading { display: none; text-align: center; margin: 20px 0; color: #666; } </style> </head> <body> <div class="container"> <h1>H5滚动截长图示例</h1> <div class="controls"> <button id="captureBtn">生成截图</button> <button id="downloadBtn" disabled>下载图片</button> </div> <div class="loading" id="loading">正在生成截图,请稍候...</div> <div id="result"></div> <div id="content"> <h2>测试内容区域</h2> <div id="longContent"></div> <div id="capter" style="height: 600px;width: calc(100% - 20px);background: orange;padding: 10px;">你好,测试截图</div> </div> </div> <script> // 生成测试内容 const longContent = document.getElementById('longContent'); for (let i = 1; i <= 20; i++) { const section = document.createElement('div'); section.className = 'section'; section.innerHTML = ` <div id="section_${i}"> <h3>第 ${i} 部分</h3> <p>这是自动生成的测试内容段落 ${i},用于演示长页面截图功能。</p> </div> `; longContent.appendChild(section); } let generatedImage = null; document.getElementById('captureBtn').addEventListener('click', async function() { const loading = document.getElementById('loading'); const result = document.getElementById('result'); const captureBtn = document.getElementById('captureBtn'); const downloadBtn = document.getElementById('downloadBtn'); loading.style.display = 'block'; result.innerHTML = ''; captureBtn.disabled = true; try { // 获取整个文档高度 const body = document.body; const html = document.documentElement; const height = Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ); // 使用html2canvas截图 const canvas = await html2canvas(document.querySelector("#capter"), { scale: 2, // 高清截图 scrollY: -window.scrollY, // 修正滚动位置 windowHeight: height, // 设置窗口高度为整个页面高度 useCORS: true, // 允许跨域图片 allowTaint: true, logging: true }); generatedImage = canvas.toDataURL('image/png'); result.innerHTML = `<img src="${generatedImage}" style="max-width:100%; border:1px solid #ddd; border-radius:5px;">`; downloadBtn.disabled = false; } catch (error) { console.error('截图失败:', error); result.innerHTML = `<p style="color:red;">截图失败: ${error.message}</p>`; } finally { loading.style.display = 'none'; captureBtn.disabled = false; } }); document.getElementById('downloadBtn').addEventListener('click', function() { if (!generatedImage) return; const link = document.createElement('a'); link.download = 'fullpage-screenshot.png'; link.href = generatedImage; link.click(); }); </script> </body> </html> |
芯片:Apple M2
macOS: 13.3
react-native: 0.70.0
Xcode: 14.3.1
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#### Mac IOS 常见问题 > boost 问题修复 将 /node_modules/react-native/third-party-podspecs/boost.podspec 中对应内容修改如下: ```shell spec.source = { :http => 'https://sourceforge.net/projects/boost/files/boost/1.76.0/boost_1_76_0.tar.bz2', :sha256 => 'f0397ba6e982c4450f27bf32a2a83292aba035b827a5623a14636ea583318c41' } ``` > We ran "xcodebuild" command but it exited with error code 65. 全局将 IPHONEOS_DEPLOYMENT_TARGET 的值替换成 12.4 > "RNSScreenStackHeaderConfig" was not found in the UIManager. 1、 "react-native-safe-area-context": "^3.4.1" "react-native-screens": "3.25.0" 2、 cd ios & pod install 3、 全局将 IPHONEOS_DEPLOYMENT_TARGET 的值替换成 12.4 > make sure you`re running a package server or have included a .jsbundle file in your application bundle. 如果有提示: [oh-my-zsh] Would you like to update? [Y/n] 更新zsh后,重启ios |
@supports 兼容性很好,所以使用 @supports 做兼容是个不错的选择。
例:
|
1 2 3 4 5 6 |
@supports (padding-bottom: env(safe-area-inset-bottom)) or (padding-bottom: constant(safe-area-inset-bottom)) { .your-dom { padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */ padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS >= 11.2 */ } } |
|
1 2 3 4 5 6 7 8 |
@supports not ( (padding-bottom: env(safe-area-inset-bottom)) or (padding-bottom: constant(safe-area-inset-bottom)) ) { .your-dom { padding-bottom: 20px; } } |
一、
|
1 2 3 4 5 6 7 8 9 10 11 12 |
&::after { content: ""; position: absolute; top: -50%; bottom: -50%; left: -50%; right: -50%; border: 1px solid #e9e9e9; border-radius: 2px; -webkit-transform: scale(0.5); transform: scale(0.5); } |
二、
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
&::after { content: ""; position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform-origin: 0 0; border-width: 1px; border-style: solid; border-radius: 50%; -webkit-transform: scale(0.5); transform: scale(0.5); box-sizing: border-box; } |
方法一:
首先,在拖动 div 时,判断当前容器 div 是否有滚动条,如果没有,则禁止整个 div 拖动,例:
|
1 2 3 4 5 6 |
const list_dom: any = document.querySelector(".list"); list_dom.addEventListener("touchmove",(ev) => { if (list_dom.scrollHeight <= list_dom.clientHeight &&list_dom.offsetHeight <= list_dom.clientHeight) { ev.preventDefault(); } },{ passive: false }); |
注:上述方法仅适用于 div 内没有其他内容滚动情形!如果内层有其他[……]