javascript 3d網頁 封裝簡單的Gui控制器視圖類 和 ThreeBSP網格組合 ( three.js r114 初探 三)

来源:https://www.cnblogs.com/weihexinCode/archive/2020/03/13/12490002.html
-Advertisement-
Play Games

1 完整代碼下載 https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ 提取碼 3fzt (壓縮包名: 2020-3-12-demo.zip) 2 圖片展示 3 代碼展示 1 (function(v, f){ 2 'use strict'; 3 4 if(! ...


1 完整代碼下載

  https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ

  提取碼 3fzt (壓縮包名: 2020-3-12-demo.zip)

2 圖片展示

  

3 代碼展示

 

  1 (function(v, f){
  2     'use strict';
  3     
  4     if(!v || !f || window.Three !== undefined){return;}
  5     
  6     if(WEBGL.isWebGLAvailable() === false){//是否支持WebGL
  7         document.body.appendChild(WEBGL.getWebGLErrorMessage());
  8         return;
  9     }
 10     
 11     THREE.Cache.enabled = true;//載入器啟用緩存
 12     
 13     var Three = function (){
 14         //滑鼠平移視角功能 的 屬性
 15         this.cmtp = {
 16             speed:10, //平移速度
 17             state:{x:0, y:0}, //平移狀態
 18             size:20, //滑鼠距顯示器邊框的大小(如果滑鼠當前位置符合這個範圍則平移視角)
 19             run:false //是否啟用滑鼠平移視角功能
 20         };
 21         
 22         this.animateFunc = [];//每幀自動執行的函數列表
 23         this.sceneSize = sceneSize;//場景大小
 24         this.clock = new THREE.Clock();//跟蹤時間
 25         this.scene = scene//場景
 26         this.camera = createCamera(this.sceneSize);//相機
 27         this.renderer = createRenderer();//渲染器
 28         this.light = createLight(this.scene);//燈光
 29         this.control = createControl(this.camera, this.renderer, this.clock, this.animateFunc, this.cmtp);//控制器
 30         this.Land = Land;
 31         
 32         animate(this.scene, this.camera, this.renderer, this.animateFunc);//動畫迴圈
 33     }
 34     
 35     //布爾運算 type = intersect    交集、重合的部分 union    並集、組合、相加 subtract    差集、相減
 36     Three.prototype.getBSP = (meshA, meshB, type)=>{
 37         if(!meshA || !meshB || !type){return;}
 38         var bsp_a = new ThreeBSP(meshA);//生成ThreeBSP對象
 39         var bsp_b = new ThreeBSP(meshB);//生成ThreeBSP對象
 40         var bsp = bsp_a[type](bsp_b);//進行 type 計算
 41         var mesh = bsp.toMesh();//轉換為mesh模型
 42         mesh.geometry.computeFaceNormals();//更新模型的面
 43         mesh.geometry.computeVertexNormals();//更新模型的頂點
 44         mesh.geometry = new THREE.BufferGeometry().fromGeometry(mesh.geometry);//轉換為 buff緩衝幾何體
 45         mesh.material = meshA.material;//重賦值紋理
 46         return mesh;
 47     }
 48     
 49     //創建 場景
 50     var createScene = ()=>{
 51         var sce = new THREE.Scene();
 52         //sce.fog = new THREE.Fog(0xcce0ff, 800, 1000);//線性霧
 53         sce.background = new THREE.CubeTextureLoader()
 54         .setPath('img/cube/skyboxsun25deg/')
 55         .load( [ 'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ] );
 56         return sce;
 57     }
 58     
 59     //創建 相機
 60     var createCamera = (sceneSize)=>{
 61         var camera = new THREE.PerspectiveCamera(75, v.client.w/v.client.h, 1, sceneSize/2);
 62         camera.position.set(0, 0, 100);//相機起始位置
 63         return camera;
 64     }
 65     
 66     //創建 渲染器
 67     var createRenderer = ()=>{
 68         var renderer = new THREE.WebGLRenderer({
 69             antialias : true,//抗割齒
 70             powerPreference:"high-performance"//選擇高性能GPU渲染
 71         });
 72         renderer.setSize(v.client.w, v.client.h);//設置渲染大小
 73         renderer.setPixelRatio(window.devicePixelRatio);//渲染矯正
 74         renderer.gammaFactor = 2.2;//著色校正
 75         renderer.physicallyCorrectLights = true;//使其精確照明
 76         renderer.shadowMap.enabled = true;//渲染陰影
 77         //renderer.autoClear = true;//每幀自動清理緩存
 78         if(!renderer.extensions.get('WEBGL_depth_texture')){console.log("深度紋理擴展獲取失敗:WEBGL_depth_texture");}
 79         renderer.domElement.style.zIndex = "0";
 80         renderer.domElement.style.position = "absolute";
 81         renderer.domElement.style.top = "0px";
 82         renderer.domElement.style.left = "0px";
 83         document.body.appendChild(renderer.domElement);
 84         return renderer;
 85     }
 86     
 87     //創建 燈光
 88     var createLight = (scene)=>{
 89         scene.add(new THREE.AmbientLight(0x696969));//環境光(無處不在的光,太陽光)
 90         var l_d = 1000, light = new THREE.DirectionalLight(0xF0F8FF, 1);//平行光(產生陰影的光)
 91         light.position.set(-3000, 3000, -3000);
 92         light.position.multiplyScalar(1);
 93         //陰影
 94         light.castShadow = true;
 95         light.shadow.mapSize.width = 1024;
 96         light.shadow.mapSize.height = 1024;
 97         light.shadow.camera.left = -l_d;
 98         light.shadow.camera.right = l_d;
 99         light.shadow.camera.top = l_d;
100         light.shadow.camera.bottom = -l_d;
101         light.shadow.camera.near = 1;
102         light.shadow.camera.far = 6000;
103         scene.add(light);
104         return light;
105     }
106     
107     //創建 控制器
108     var createControl = (camera, renderer, clock, animateFunc, cmtp)=>{
109         var control = new THREE.OrbitControls(camera, renderer.domElement);
110         control.target = new THREE.Vector3(0, 0, 0);//相機焦點
111         //control.minPolarAngle = Math.PI * 0.3;//向上最大角度
112         //control.maxPolarAngle = Math.PI * 0.4;//向下最大角度
113         control.minDistance = 1;//最小距離
114         control.maxDistance = 10000;//最大距離
115         control.autoRotateSpeed = 10;//自動旋轉速度
116         //control.panSpeed = 100;//滑鼠旋轉速度
117         control.enableZoom = true;//是否啟用縮放
118         control.enableKeys = true;//是否啟用鍵盤
119         control.panSpeed = 1;//滑鼠平移速度
120         control.keyPanSpeed = 100;//按鍵平移的速度
121         control.keys.LEFT = 65;//key a左
122         control.keys.UP = 87;//key w前
123         control.keys.RIGHT = 68;//key d右
124         control.keys.BOTTOM = 83;//key s後
125         controlMousePanTargetInit(control, cmtp);//初始化滑鼠平移
126         animateFunc.push(()=>{//加入實時更新隊列
127             if(!control || !clock){return;}
128             control.update(clock.getDelta());//更新控制器
129             //滑鼠平移視角, myRunPan 方法是我在控制器插件上新加的方法(OrbitControls.js/900)
130             //有些用戶的瀏覽器設置並占用了滑鼠右鍵(預設平移鍵), 
131             if(cmtp.run === true){control.myRunPan(cmtp);}
132         });
133         return control;
134     }
135     
136     //控制滑鼠平移視角 初始化
137     var controlMousePanTargetInit = (control, cmtp)=>{
138         var w, h;
139         v.addEvent(document.body, "mousemove", (e)=>{
140             e.preventDefault();
141             if(cmtp.run !== true){return;}
142             w = v.client.w - e.clientX;
143             h = v.client.h - e.clientY;
144             
145             if(w < cmtp.size){cmtp.state.x = 2;}
146             else if(w > v.client.w - cmtp.size){cmtp.state.x = 1;}
147             else{cmtp.state.x = 0;}
148             
149             if(h < cmtp.size){cmtp.state.y = 2;}
150             else if(h > v.client.h - cmtp.size){cmtp.state.y = 1;}
151             else{cmtp.state.y = 0;}
152         });
153     }
154     
155     //創建 動畫迴圈
156     var k, len, animate = (scene, camera, renderer, animateFunc)=>{
157         requestAnimationFrame(()=>{animate(scene, camera, renderer, animateFunc);});
158         len = animateFunc.length;
159         for(k = 0; k < len; k++){animateFunc[k]();}
160         renderer.render(scene, camera);
161     }
162     
163     
164 
165     var Land = function (){
166         land.group.add(new THREE.GridHelper(sceneSize, 100));//添加網格輔助線
167         scene.add(land.group);
168         this.name = land.name;
169         this.group = land.group;
170         this.meshs = land.meshs;
171     }
172 
173     //創建 所有的成形紋理
174     var land_texture = (object)=>{
175     //parameter:
176         //texNum:number 載入紋理數量 預設值為最大值 this.textureMax
177         //texture.repeat.set(25, 25);//x y 貼圖平鋪次數
178         //texture.anisotropy = 1024;//紋理的清晰度(值為2的幕:1, 2, 4, 8, ... 512, 1024, 2048, ...)
179         //texture.matrixAutoUpdate = false;//是否自動更新矩陣
180         //texture.updateMatrix();//手動更新矩陣
181         //texture.needsUpdate = true;//下次使用紋理時觸發一次更新
182         var o = object || {};
183         var num = o.texNum === undefined ? land.textureMax : o.texNum;
184         if(typeof(num) !== "number" || num === 0){return;}
185         
186         var map = new Map(), load = new THREE.TextureLoader();
187         var k, loading = (index, url)=>{
188             let texture = load.load(url);
189             texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
190             texture.anisotropy = 1024;
191             texture.matrixAutoUpdate = false;
192             texture.updateMatrix();
193             map.set(index, texture);
194         }
195         for(k = 0; k < num; k++){loading(k, "img/texture/land/"+k+".jpg");}
196         //setTimeout(()=>{if(map.size === num){console.log("下載圖片完成");}}, 3000);
197         return map;
198     }
199     
200     //創建 所有的 成形材質
201     var land_material = ()=>{
202         var k, map = new Map();
203         for(k = 0; k < land.textures.size; k++){
204             map.set(k, new THREE.MeshLambertMaterial({map:land.textures.get(k), transparent:false}));
205         }
206         map.set(land.textures.size, new THREE.MeshLambertMaterial({color:land.color, transparent:false}));
207         return map;
208     }
209     
210     //創建 所有的 成形的幾何體
211     var land_geometry = ()=>{
212         
213     }
214     
215     //all mesh
216     var land_mesh = ()=>{
217         var map = new Map();
218         var g = new THREE.BoxGeometry(256, 256, 50);
219         map.set(0, new THREE.Mesh(g, land.materials.get(0)));
220         map.set(1, new THREE.Mesh(g, land.materials.get(1)));
221         
222         return map;
223     }
224 
225 
226 
227     var sceneSize = 5000;
228     var scene = createScene();
229     var land = {
230         name : "land",
231         textureMax : 5, 
232         color : 0x00ff00,
233         group : new THREE.Group()
234     }
235     land.group.name = "group_land";
236     land.textures = land_texture();
237     land.materials = land_material();
238     land.geometrys = land_geometry();
239     land.meshs = land_mesh();
240     
241     
242     
243     window.Three = new Three();
244 
245 }(new View(), new Func()))
initThree.js

 

  1 /** 視圖類
  2     Gui(a, b, c, d, e):
  3         //介紹: 通過 修改控制器可視視圖 來 更新 a引用對象里的屬性值, (Gui類的位置在View類的原型里)
  4         //暫支持屬性類型: number(計量控制器), function(按鈕), boolean(覆選框)
  5         //在預設渲染所有a對象屬性的時候,不符合的屬性會自動忽略掉
  6         //控制器視圖 與 a引用對象 預設是雙向綁定的, 所以它會覆蓋掉原有的get與set
  7         a : object 必須, 目標對象(引用)
  8         b : array 可選, 選擇性的渲染a裡面屬性, 如果不等於array則預設渲染全部a對應的屬性名, 反之通過b數組裡的字元串渲染對應a對象里的屬性名
  9         c : array[min -1, max 1, step 0.1] 可選, a對象如果有多個number類型並有不同的min max step值,則需要用對象包裹,{string:[min, max, step], ...} (string必須對應a對象的屬性名)
 10         d : string 可選, 塊的標題, 預設 "class"
 11         e : boolean 可選, 是否雙向綁定, 預設為 true
 12     例: v = new View()//,每new一次Gui都會新增一個 標題分格線 就是 塊, 點擊title會隱藏此塊
 13         new v.View().Gui(THREE);
 14         new v.Gui(THREE);//渲染全部THREE對象里符合類型的屬性
 15         new v.Gui(THREE, ["NeverDepth"]);//c預設為[-1, 1, 0.1]
 16         new v.Gui(THREE, ["NeverDepth"], {NeverDepth:[-200, 200, 10]});
 17         new v.Gui(THREE, ["NeverDepth"], [-200, 200, 10]);
 18         new new View().Gui(THREE, null, {NeverDepth:[-200, 200, 10]});
 19 */
 20 class View{
 21     
 22     constructor(){
 23         if(!this.client){this.getClient();}
 24         if(!this.Gui){this.getGui();}
 25     }
 26     
 27     //創建html元素
 28     add(fel, elemName, id, cls){
 29         //創建一個元素
 30         let el = document.createElement(elemName);
 31         //設置el id 和 class
 32         if(id){el.setAttribute('id',id);}
 33         if(cls){el.className = cls;}
 34         //把el添加到fel並顯示(渲染el)
 35         if(fel){fel.appendChild(el);}
 36         return el;
 37     }
 38 
 39     //刪除html元素
 40     remove(){
 41         let k, arg = arguments, err = [];
 42         for(k = 0; k < arg.length; k++){
 43             if(this.isEl(arg[k]) === false){err.push(arg[k]); continue;}
 44             arg[k].parentNode.removeChild(arg[k]);
 45         }
 46         if(err.length > 0){return {err:'這裡有一些刪除失敗的元素', arr:err};}
 47         return true;
 48     }
 49 
 50     //id獲取html元素
 51     get(id){
 52         return document.getElementById(id);
 53     }
 54     
 55     //獲取可視寬高
 56     getClient(){
 57         View.prototype.client = {
 58             w:document.documentElement.clientWidth || document.body.clientWidth || window.innerWidth, 
 59             h:document.documentElement.clientHeight || document.body.clientHeight || window.innerHeight,
 60         };
 61     }
 62     
 63     //通過parentNode檢查元素是否存在於頁面中
 64     isEl(el){
 65         if(typeof(el) !== 'object'){return false;}
 66         //被刪除之後的html元素object的 parentNode等於null
 67         if(!el.parentNode){return false;}
 68         return true;
 69     }
 70     
 71    //元素綁定事件
 72    addEvent(target, ev, callback){
 73         target.addEventListener(ev, function(e){e.preventDefault(); if(callback){callback(e);}}, false);
 74    }
 75     
 76     removeEvent(target, ev, callback){
 77         target.removeEventListener(ev, (e)=>{if(callback)callback(e);}, false);
 78     }
 79     
 80     //創建控制器元素
 81     getGui(){
 82         var tar = this, timer = 0, timerMax = 10, _isBind = true;
 83         var elem = this.add(document.body, 'div', 'GuiId', 'box-shadown box-scroll-block');
 84         
 85         var o = function (obj, data, info, title, isBind){
 86             this.obj = obj;
 87             if(typeof(this.obj) !== "object"){return;}
 88             if(typeof(isBind) === "boolean"){_isBind = isBind;}
 89             this.arr = [];
 90             var k, bs = [], fs = [], ns = [];
 91             var ti = title || "calss", fel = line(ti, timer++);
 92             var T = typeof(data), A = Array.isArray(data);
 93             
 94             if(!data){for(k in this.obj){this.arr.push(k);}}
 95             else if(A === true){this.arr = data;}
 96             else if(T !== "object"){this.arr.push(data);}
 97             else{return;}
 98             
 99             var len = this.arr.length;
100             for(k = 0; k < len; k++){
101                 T = typeof(this.obj[this.arr[k]]);
102                 if(T === "boolean"){bs.push(this.arr[k]);}
103                 else if(T === "function"){fs.push(this.arr[k]);}
104                 else if(T === "number"){ns.push(this.arr[k]);}
105                 else{continue;}
106             }
107             check(obj, bs, fel);
108             click(obj, fs, fel);
109             range(obj, ns, info || {}, fel);
110         }
111         
112         o.prototype.elem = elem;
113         
114         //添加 覆選框(boolean) fel.appendChild(el);
115         var check = function (obj, arr, fel){
116             var p = tar.add(fel, 'p'), size = 0;
117             
118             var create = (val)=>{
119                 let i = tar.add(p, 'input');
120                 let s = tar.add(p, 'span');
121                 i.type = "checkbox";
122                 i.checked = obj[val];
123                 s.innerHTML = " "+val+", ";
124                 tar.addEvent(i, 'change', (e)=>{obj[val] = e.target.checked;});
125                 size += i.offsetWidth;
126                 size += s.offsetWidth;
127                 return {i:i, s:s};
128             }
129             
130             var k, len = arr.length;
131             for(k = 0; k < len; k++){
132                 let el_f = create(arr[k]);
133                 if(size > 280 && k !== 0){
134                     tar.remove(el_f.i, el_f.s); 
135                     arr.splice(0, k); 
136                     check(obj, arr, fel);
137                     return;
138                 }
139                 bind(obj, arr[k], (old, now)=>{el_f.i.checked = now; return now;});
140             }
141         }
142         
143         //添加 按鈕(function)
144         var click = function (obj, arr, fel){
145             var p = tar.add(fel, 'p'), size = 0;
146             
147             var create = (val)=>{
148                 let i = tar.add(p, 'input');
149                 let s = tar.add(p, 'span');
150                 i.type = "button";
151                 i.value = val;
152                 s.innerHTML = ", ";
153                 tar.addEvent(i, 'click', obj[val]);
154                 size += i.offsetWidth;
155                 size += s.offsetWidth;
156                 return {i:i, s:s};
157             }
158             
159             var k, len = arr.length;
160             for(k = 0; k < len; k++){
161                 let el_f = create(arr[k]);
162                 if(size > 280 && k !== 0){
163                     tar.remove(el_f.i, el_f.s);
164                     arr.splice(0, k); 
165                     click(obj, arr, fel);
166                     return;
167                 }
168             }
169         }
170         
171         //添加 計量控制器(number) info: object 可選 預設[min -1, max 1, step0.1]
172         var range = function (obj, arr, info, fel){
173             var di = [-1, 1, 0.1]; if(Array.isArray(info) === true){di = info;}
174             
175             var create = (val)=>{
176                 let c = info[val] || di; if(c[2] < 0){c[2] = 1;}
177                 if(obj[val] < c[0] || obj[val] > c[1]){return;}
178                 let p = tar.add(fel, 'p'), i = tar.add(p, 'input');
179                 i.type = "range"; i.value = obj[val]; i.min = c[0]; i.max = c[1]; i.step = c[2];
180                 let nul = tar.add(p, 'span'); nul.innerHTML = " ";
181                 let is = tar.add(p, 'input'); is.type = "tel"; is.value = obj[val];
182                 let key = false, x, xs, s = tar.add(p, 'span'); s.innerHTML = " "+val;
183                 
184                 let getNum = (num)=>{
185                     if(num === obj[val]){return;}
186                     if(typeof(num) !== "number" || isNaN(num) === true){
187                         i.value = obj[val]; is.value = obj[val]; 
188                         return;
189                     }
190                     if(num > c[0] && num < c[1]){
191                         return num;
192                     }else if(num > c[0]){
193                         return c[1];
194                     }else if(num < c[1]){
195                         return c[0];
196                     }
197                 }
198<

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目前負責的一個項目,需要維護一個電話號碼對比庫,表名為phone_bak1,以下稱為a表,量級為3000萬條。還有另外一張表存儲電話白名單,表名為phone_delete,以下稱為b表,量級為3000條左右。 目的呢,是要從a表中排除掉在b表中的電話號碼。 我直接使用以下語句: DELETE FRO ...
  • 資料庫版本及優勢 3.4版本在性能和安全性等方面較3.2版本均有不同程度的提升; 4.0版本更適用於金融等對事務有依賴且使用NoSQL特性的場景; 4.2版本採用二段提交方式,保證分片集群事務的ACID特性,極大拓展了適用的業務場景。更多詳情請參見下表。 資料庫版本優勢 3.4版本 更快的主備同步 ...
  • 場景 Centos中Redis的下載編譯與安裝(超詳細): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103967334 Redis的啟動和關閉(前臺啟動和後臺啟動): https://blog.csdn.net/BADAO_ ...
  • [20200312]不要設置net.ipv4.tcp_tw_recycle=1.txt--//昨天認真看了2篇blog:https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux--//中文翻譯:http://www.cnxct. ...
  • 場景 Centos中Redis的下載編譯與安裝(超詳細): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103967334 Redis的啟動和關閉(前臺啟動和後臺啟動): https://blog.csdn.net/BADAO_ ...
  • This document describes the internal formats of the Paradox data and index files ...
  • 場景 進程: 一個Android應用就是一個一個進程,每個應用在各自的進程中運行。 線程: 比進程更小的獨立運行的基本單位,一個進程可以包含多個線程。 要求: 一個TextView和一個Button,點擊Button後新開一個線程更改TextView的內容。 修改activity_main.xml, ...
  • 不知道大家有沒有註意到這麼個問題: 在最新創建項目的時候,有了 這樣一個選項。可能你還不知道 的意思,可以這樣理解,androidx 代替了之前的一系列的 庫。如果你選擇了 就表示在你新創建的項目裡面使用的支持庫就是 了而不是之前我們用的 類型的支持庫了。 假設這裡不勾選那麼就說明我們依然使用之前的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...