主頁 > 企業開發 > 網頁小實驗——在平面空間建立大量“可思考的”物件

網頁小實驗——在平面空間建立大量“可思考的”物件

2021-01-24 18:51:56 企業開發

實驗目標:建立大量物件(萬級),為每個物件設定自身邏輯,并實作物件之間的互動,以原生DOM為渲染方式,主干在于物件邏輯,可根據需求換用其他渲染方式,

一、html舞臺:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>比較整體重繪和移動重繪的效率</title>
 6     <link href="../../CSS/newland.css" rel="stylesheet">
 7     <style>
 8         div{position: absolute}
 9         #div_allbase,#div_map{background-color: darkseagreen}
10         .div_unit{background-repeat: no-repeat;background-size: 100% 100%}
11     </style>
12     <script src="../../JS/MYLIB/newland.js"></script>
13     <script src="./ais.js"></script>
14     <script src="./dos.js"></script>
15     <script src="./commands.js"></script>
16     <script src="./vectorTools.js"></script>
17 </head>
18 <body>
19 <div id="div_allbase" style="width: 100%;height: 100%">
20     <div id="div_map" ></div>
21     <div id="fps" style="z-index: 302;position:fixed"></div>
22     <div id="div_console" style="z-index: 302;position: fixed;height: 60px;width: 100%;bottom:0px;background-color: #cccccc">
23         <div id="div_minimap" style="position:fixed;height:60px;width: 80px;left:0px;bottom:0px;background-color: darkseagreen;overflow: hidden">
24             <div id="div_miniview" style="position:absolute;background-color: #ffffff"></div>
25         </div>
26         <button class="btn_console" onclick="changeView('上')"></button>
27         <button class="btn_console" onclick="changeView('下')"></button>
28         <button class="btn_console" onclick="changeView('左')"></button>
29         <button class="btn_console" onclick="changeView('右')"></button>
30         <button class="btn_console" onclick="changeView('放大')">放大</button>
31         <button class="btn_console" onclick="changeView('縮小')">縮小</button>
32         <br>
33         <button class="btn_console" onclick="runOneStep()">步進</button>
34         <button class="btn_console" onclick="runLoop()">自動</button>
35         <button class="btn_console" onclick="stopRunLoop()">暫停</button>
36     </div>
37 
38 </div>
39 </body>
40 <script>
41 //主體程式入口
42 </script>
43 </html>

 

其中“div_map”是大量單位的繪制區域,“fps”是顯示幀率的標簽沒有使用,“div_console”是位于螢屏底部的控制區域,其中包括一些控制場景運行的按鈕和一個顯示視窗位置的迷你地圖,

二、場景初始化

1、初始化前的準備:

 1  window.onload=beforeInit;
 2     function beforeInit()
 3     {
 4         //這里可以做一些運行環境檢測和渲染方式選擇操作
 5         Init();
 6     }
 7     var obj_units={};//用id索引所有單位
 8     var obj_unitclassed={};//用class索引所有單位型別
 9     var arr_part=[];//多重陣列,地圖分塊,優化單位查找速度,最下層是陣列
10     var arr_partowner=[];//多重陣列,用來分塊優化勢力占據,最下層是物件
11     var obj_owners={
12         red:{color:"red",name:"red",arr_unit:[],countAlive:0},
13         blue:{color:"blue",name:"blue",arr_unit:[],countAlive:0}
14     }//所有勢力
15     var div_allbase,div_map;
16     var mapWidth=4096*2,mapHeight=3072*2,partSizeX=200,partSizeY=200;//地圖寬度、地圖高度、每個地圖分塊的尺寸
17     var flag_runningstate="beforeStart";//系統總體運行狀態(未用到)
18     var flag_autorun=false;//是否自動運行,默認非自動運行,點擊一次“步進”按鈕計算一次,
19     function Init()
20     {
21       //初始化代碼      
22     }

其中arr_part和arr_partowner用來把地圖分成多塊,這樣一個單位在尋找其他單位時就可以從臨近的小塊找起,不必遍歷地圖上的所有單位,把這樣的陣列稱為“索引陣列”,

2、初始化地圖

 1 //InitMap
 2         div_allbase=document.getElementById("div_allbase");
 3         div_map=document.getElementById("div_map");
 4         div_map.style.width=mapWidth+"px";
 5         div_map.style.height=mapHeight+"px";
 6         var partCountX=Math.ceil(mapWidth/partSizeX);
 7         var partCountY=Math.ceil(mapHeight/partSizeY);
 8         for(var i=0;i<partCountX;i++)//為地圖上的每個區域分配一個陣列元素
 9         {
10             var arr=[];
11             for(var j=0;j<partCountY;j++)
12             {
13                 arr.push([]);
14             }
15             arr_part.push(arr);
16 
17             var arr=[];
18             for(var j=0;j<partCountY;j++)
19             {
20                 arr.push({});
21             }
22             arr_partowner.push(arr);
23         }

3、初始化控制按鈕

 1 //InitUI
 2         var arr_btn=document.getElementsByClassName("btn_console");
 3         arr_btn[0].onclick=function(){changeView('上')};
 4         arr_btn[1].onclick=function(){changeView('下')};
 5         arr_btn[2].onclick=function(){changeView('左')};
 6         arr_btn[3].onclick=function(){changeView('右')};
 7         arr_btn[4].onclick=function(){changeView('放大')};
 8         arr_btn[5].onclick=function(){changeView('縮小')};
 9         var div_miniview=document.getElementById("div_miniview");
10         div_miniview.style.width=80*(window.innerWidth/mapWidth)/Math.pow(2,zoomRate)+"px";
11         div_miniview.style.height=60*(window.innerHeight/mapHeight)/Math.pow(2,zoomRate)+"px";
12         window.onresize=function(){
13             var div_miniview=document.getElementById("div_miniview");
14             div_miniview.style.width=80*(window.innerWidth/mapWidth)/Math.pow(2,zoomRate)+"px";
15             div_miniview.style.height=60*(window.innerHeight/mapHeight)/Math.pow(2,zoomRate)+"px";
16         }

其中“zoomRate”是地圖的縮放比例,“div_miniview”在迷你地圖里表示可視區域,當縮放比例放大時,單位變大,視窗中可見的單位變少,迷你地圖的可視區域變小,

4、初始化單位型別:

 1 //InitUnitCalss
 2         var Yt=function(p){//構造野兔類,并且為它設定一些屬性
 3             this.className="Yt";
 4             this.hp=10;
 5             this.mp=0;
 6             this.sp=10;
 7             this.at=2;
 8             this.df=1;
 9             this.clipSize=20;//碰撞尺寸
10             this.nearAttRange=20;//近戰攻擊范圍
11             this.pic="./yetu.jpg";
12             this.obj_skills={};//技能串列
13             this.left=p.left;//位置
14             this.top=p.top;
15             this.id=p.id;
16             this.owner=p.owner;//所屬勢力
17             this.doing="standing";//正在做的事
18             this.wanting="waiting";//想要做的事
19             this.being="free";//正在遭受
20             this.speed=50;//移動速度
21             this.view=500;//視野
22         }
23         Yt.prototype.render=function(){//渲染方法
24             if(this.doing=="dead")
25             {
26                 return "<div class='div_unit' " +
27                     "style='background-color:black;" +
28                     "width:"+this.clipSize+"px ;height:"+this.clipSize+"px;left:"+this.left+"px;top:"+this.top+"px;" +
29                     "border:2px solid "+this.owner.color+"'>" +
30                     "</div>"
31             }
32             if(zoomRate>=2)
33             {
34                 return "<div class='div_unit' " +
35                     "style='background-image: url("+this.pic+");" +
36                     "width:"+this.clipSize+"px ;height:"+this.clipSize+"px;left:"+this.left+"px;top:"+this.top+"px;" +
37                     "border:2px solid "+this.owner.color+"'>" +
38                         "<div style='background: inherit;width: 100%;height:100%;zoom: 0.1;font-size: 12px;overflow: hidden;color:"+this.owner.color+"'>" +
39                             "<div style='top:20px'>doing:"+this.doing+"</div>" +
40                             "<div style='top:40px'>wanting:"+this.wanting+"</div>" +
41                             "<div style='top:60px'>being:"+this.being+"</div>" +
42                     "</div>" +
43                     "</div>"
44             }
45             else if(zoomRate>=-1)
46             {
47                 return "<div class='div_unit' " +
48                     "style='background-image: url("+this.pic+");" +
49                     "width:"+this.clipSize+"px ;height:"+this.clipSize+"px;left:"+this.left+"px;top:"+this.top+"px;" +
50                     "border:2px solid "+this.owner.color+"'>" +
51                     "</div>"
52             }
53             else
54             {
55                 return "<div class='div_unit' " +
56                     "style='" +
57                     "width:"+this.clipSize+"px ;height:"+this.clipSize+"px;left:"+this.left+"px;top:"+this.top+"px;" +
58                     "border:2px solid "+this.owner.color+"'>" +
59                     "</div>"
60             }
61 
62         }
63         Yt.prototype.think=obj_ais.近戰戰士;//思考方式
64         Yt.prototype.do=obj_dos.DOM;//渲染方式,2d網頁標簽的渲染
65         obj_unitclassed.Yt=Yt;

這里根據當前縮放比例的不同為野兔設定了不同的渲染方式,縮放比例大時顯示更多細節,其中“pic”屬性是代表野兔的圖片:

5、初始化單位:

 1 //InitUnit
 2         for(var i=0;i<10000;i++)//隨機建立10000只野兔
 3         {
 4             var obj_yt=new obj_unitclassed.Yt({left:newland.RandomBetween(500,mapWidth-500),top:newland.RandomBetween(500,mapHeight-500)
 5                 ,id:"yt_"+i,owner:newland.RandomChooseFromObj(obj_owners)});
 6             obj_units[obj_yt.id]=obj_yt;
 7             var arr_unit=obj_owners[obj_yt.owner.name].arr_unit;
 8             obj_yt.ownerNumber=arr_unit.length;
 9             arr_unit.push(obj_yt);
10         }
11         obj_owners.red.countAlive=obj_owners.red.arr_unit.length;
12         obj_owners.blue.countAlive=obj_owners.blue.arr_unit.length;
13         列方陣("blue",{left:2000,top:4000},Math.PI/6,100,20,obj_owners);
14         列方陣("red",{left:6000,top:4000},Math.PI*7/6,100,20,obj_owners);
15         for(var key in obj_units)
16         {
17             var obj_yt=obj_units[key];
18             obj_yt.left=obj_yt.target[0].left;
19             obj_yt.top=obj_yt.target[0].top;
20             obj_yt.target=[];
21             obj_yt.wanting="waiting";
22 
23             obj_yt.x=Math.floor(obj_yt.left/partSizeX);
24             obj_yt.y=Math.floor(obj_yt.top/partSizeY);
25             arr_part[obj_yt.x][obj_yt.y].push(obj_yt);
26             var obj_temp=arr_partowner[obj_yt.x][obj_yt.y];
27             if(!obj_temp[obj_yt.owner.name])
28             {
29                 obj_temp[obj_yt.owner.name]=1;
30             }
31             else
32             {
33                 obj_temp[obj_yt.owner.name]++;
34             }
35         }

其中“列方陣”方法是寫在command.js中的一個“命令方法”,可以在程式運行時執行這些命令方法改變單位的wanting屬性,進而引導單位接下來的行為,command.js內容如下:

 1 function 列方陣(ownerName,pos,angle,col,dis,obj_owners)//勢力名、方陣左上角位置、方陣從right方向起順時針旋轉角度、方陣每行最大人數(也就是最大列數)、單位間距、勢力串列
 2 {
 3     var arr_unit=obj_owners[ownerName].arr_unit;
 4     var len=arr_unit.length;
 5     for(var i=0;i<len;i++)
 6     {
 7         var unit=arr_unit[i];
 8         if(unit.doing!="dead"&&unit.doing!="unconscious")
 9         {
10             unit.wanting="lineup";//單位想要去排隊
11             var left0=(i%col)*dis;
12             var top0=Math.floor(i/col)*dis;
13             var r0=Math.pow(left0*left0+top0*top0,0.5);
14             var angle0
15             if(left0==0)
16             {
17                 angle0=Math.PI/2;
18             }
19             else
20             {
21                 angle0=Math.atan(top0/left0);
22             }
23             var angle1=angle0+angle;
24             var left1=Math.max(pos.left+r0*Math.cos(angle1),0);
25             var top1=Math.max(pos.top+r0*Math.sin(angle1));
26             unit.target=[{left:left1,top:top1}];//單位想要去這里
27         }
28     }
29 }
30 function 自由沖鋒(ownerName,obj_owners,targetName){//為每個單位選擇單獨的目標最少需要消耗十幾毫秒(加trycatch的情況下),去掉trycatch速度提升百倍
31     var arr_unit=obj_owners[ownerName].arr_unit;
32     var len=arr_unit.length;
33     for(var i=0;i<len;i++)
34     {
35         var unit=arr_unit[i];
36         if(unit.doing!="dead"&&unit.doing!="unconscious")
37         {
38             unit.wanting="freecharge";
39             unit.target=[targetName]
40         }
41     }
42 }

可以看到“列方陣”方法為勢力中的所有物件分配了一個方陣位置,然后初始化方法直接把target設為單位當前位置,這樣10000只野兔剛出場時就是排號方陣的,

接下來計算每個單位屬于arr_part和arr_partowner的哪個小塊,

6、初始化渲染和渲染回圈:

1 //TestRender
2         div_map.style.zoom=Math.pow(2,zoomRate)+'';//對單位顯示區應用地圖縮放
3         renderMap();
4         自由沖鋒("blue",obj_owners,"red");
5         自由沖鋒("red",obj_owners,"blue");
6 
7         //InitRenderLoop
8         Loop();

其中renderMap方法用來繪制單位顯示區:

function renderMap(){
        //繪制整個地圖,考慮到運行效率,只render當前顯示范圍內的!!!!,那么移動時也要重新繪制!!??
        var innerWidth=window.innerWidth;
        var innerHeight=window.innerHeight;
        var left=parseInt(div_map.style.left||0);
        var top=parseInt(div_map.style.top||0);
        var y1=(-top);///Math.pow(2,zoomRate);//畫面縮小時,同樣的地圖位移意味著更多的距離
        var x1=(-left);///Math.pow(2,zoomRate);
        var y2=y1+innerHeight/Math.pow(2,zoomRate);
        var x2=x1+innerWidth/Math.pow(2,zoomRate);//以上找到了可視區域
        var arr_temp=[];
        for(var key in obj_units)
        {
            var unit=obj_units[key];
            if(unit.left>(x1-unit.clipSize)&&unit.left<x2&&unit.top>(y1-unit.clipSize)&&unit.top<y2)
            {//繪制可視區域內的單位
                arr_temp.push(obj_units[key].render());
            }

        }
        div_map.innerHTML=arr_temp.join("");//一次性繪制
    }

繪制顯示區有兩種思路,一是一次性繪制顯示區中的所有單位,這樣移動視口時就不必重新繪制單位;而是只繪制顯示在顯示區域內的單位,視口改變時臨時繪制新顯示出的單位,經過實驗,在當前配置下第二種方式的繪制速度遠大于第一種,

繪制代碼的最后,把每個單位的render方法回傳的html文本合并起來一次性繪制,這樣做的繪制速度遠遠高于分別繪制每一單位(數百倍到上千倍),其原理在于每條修改innerHTML或createElement的操作都會觸發一次js引擎到瀏覽器渲染引擎的通信,之后瀏覽器渲染引擎將對頁面進行繪制,而js引擎將掛起等待繪制完成,并且此程序中的js掛起時間遠大于js計算和通信時間,一次性繪制則可以節省掉大量的頁面繪制次數,能夠大大提升渲染速度,

順便記錄這種一次性繪制與React“虛擬DOM”的關系——事實上React的底層繪制仍然是使用createElement建立每個標簽,并沒有實作一次性繪制,而虛擬DOM的特點在于“把所有createElement集中起來一起執行,在統一執行前,合并對同一標簽的反復修改并檢查虛擬DOM有無變化,如虛擬DOM無變化則不執行”,以此減少繪制次數,

可以用谷歌瀏覽器的performance功能配合以下程式測驗這一區別:(以下內容缺乏大量充分試驗,并且與本文主干無關)

組件:

 1 import { Component, Fragment } from "react";
 2 
 3 //測驗setState和傳統dom操作的性能差距
 4 class App extends Component {
 5     constructor(props){
 6         super();
 7         this.state={
 8             arr:[],
 9         }
10 
11     }
12     onClick1=()=>{
13         console.log(new Date().getTime())
14         var arr=[];
15         for(var i=0;i<10000;i++)
16         {
17             arr.push({key:i});
18         }
19         this.setState({arr:arr});
20     }
21     componentDidUpdate()
22     {
23         console.log(new Date().getTime())
24     }
25     onClick2=()=>{
26         console.log(new Date().getTime());
27         var div_allbase=document.getElementById("div_allbase");
28         for(var i=0;i<10000;i++)
29         {
30             var div=document.createElement("div")
31             div.innerHTML=i;
32             div_allbase.appendChild(div);
33         }
34         console.log(new Date().getTime());
35     }
36     onClick3=()=>{
37         console.log(new Date().getTime());
38         var div_allbase=document.getElementById("div_allbase");
39         var div0=document.createElement("div")
40         for(var i=0;i<10000;i++)
41         {
42             var div=document.createElement("div")//這一步還是有多余的js引擎到dom引擎的通信
43             div.innerHTML=i;
44             div0.appendChild(div);
45         }
46         div_allbase.appendChild(div0);
47         console.log(new Date().getTime());
48     }
49     onClick4=()=>{
50         console.log(new Date().getTime());
51         var div_allbase=document.getElementById("div_allbase");
52         var str="";
53         var arr=[];
54         for(var i=0;i<10000;i++)
55         {
56             arr.push("<div>"+i+"</div>");
57         }
58         str=arr.join("");
59         div_allbase.innerHTML=str;
60         console.log(new Date().getTime());
61     }
62     render() {
63         const { count, price,show } = this.state;
64         return <Fragment>
65             <button onClick={()=>this.onClick1()}>setState方法</button>
66             <button onClick={()=>this.onClick2()}>Dom方法</button>
67             <button onClick={()=>this.onClick3()}>一次添加方法</button>
68             <button onClick={()=>this.onClick4()}>innerHTML方法</button>
69             <div id={"div_allbase"} style={{}}>
70                 {this.state.arr.map(d=><div key={d.key}>{d.key}</div>) }
71              </div>
72         </Fragment>
73     }
74 }
75 
76 export default App;
View Code

index.js

 1 import React from 'react';
 2 import ReactDOM from 'react-dom';
 3 import './index.css';
 4 import App from './test2/App4';
 5 
 6 ReactDOM.render(
 7   <React.StrictMode>
 8     <App />
 9   </React.StrictMode>,
10   document.getElementById('root')
11 );
View Code

package.json:

 1 {
 2   "name": "my-app4",
 3   "version": "0.1.0",
 4   "private": true,
 5   "dependencies": {
 6     "@testing-library/jest-dom": "^5.11.4",
 7     "@testing-library/react": "^11.1.0",
 8     "@testing-library/user-event": "^12.1.10",
 9     "antd": "^4.9.2",
10     "babylonjs": "^4.2.0",
11     "codeflask": "^1.4.1",
12     "moment": "^2.29.1",
13     "react": "^17.0.1",
14     "react-dom": "^17.0.1",
15     "react-router-dom": "^5.2.0",
16     "react-scripts": "4.0.1",
17     "web-vitals": "^0.2.4"
18   },
19   "scripts": {
20     "start": "react-scripts start",
21     "build": "react-scripts build",
22     "test": "react-scripts test",
23     "eject": "react-scripts eject"
24   },
25   "eslintConfig": {
26     "extends": [
27       "react-app",
28       "react-app/jest"
29     ]
30   },
31   "browserslist": {
32     "production": [
33       ">0.2%",
34       "not dead",
35       "not op_mini all"
36     ],
37     "development": [
38       "last 1 chrome version",
39       "last 1 firefox version",
40       "last 1 safari version"
41     ]
42   }
43 }
View Code

結果,單純從一次渲染大量標簽的速度來看React的setState<每個標簽單獨appendChild<先將大量標簽放在一個容器中,然后把容器append到body<使用innerHTML一次性修改,

以下是分別渲染100000個div時的耗時情況:

 

 

 7、視口移動和縮放

 1 var sizeStep=250;
 2     var zoomRate=-3;
 3     var scrollTop=0,scrollLeft=0;
 4     function changeView(type){
 5         var div_miniview=document.getElementById("div_miniview");
 6         if(type=="上")
 7         {
 8             scrollTop=scrollTop+sizeStep/Math.pow(2,zoomRate);//畫面放大時,卷屏更慢
 9             if(scrollTop>0)
10             {
11                 scrollTop=0;
12 
13             }
14             div_map.style.top=scrollTop+"px";
15             renderMap();
16             div_miniview.style.top=-60*(scrollTop/mapHeight)+"px";
17         }
18         else if(type=="下")
19         {
20             scrollTop=scrollTop-sizeStep/Math.pow(2,zoomRate);
21             if(scrollTop<-mapHeight)
22             {
23                 scrollTop=-mapHeight;
24 
25             }
26             div_map.style.top=scrollTop+"px";
27             renderMap();
28             div_miniview.style.top=-60*(scrollTop/mapHeight)+"px";
29         }
30         else if(type=="左")
31         {
32             scrollLeft=scrollLeft+sizeStep/Math.pow(2,zoomRate);
33             if(scrollLeft>0)
34             {
35                 scrollLeft=0;
36             }
37             div_map.style.left=scrollLeft+"px";
38             renderMap();
39             div_miniview.style.left=-80*(scrollLeft/mapWidth)+"px";
40         }
41         else if(type=="右")
42         {
43             scrollLeft=scrollLeft-sizeStep/Math.pow(2,zoomRate);
44             if(scrollLeft<-mapWidth)
45             {
46                 scrollLeft=-mapWidth;
47             }
48             div_map.style.left=scrollLeft+"px";
49             renderMap();
50             div_miniview.style.left=-80*(scrollLeft/mapWidth)+"px";
51         }
52         else if(type=="放大")
53         {
54             zoomRate++;
55             if(zoomRate>3)
56             {
57                 zoomRate=3;
58             }
59 
60             div_map.style.zoom=Math.pow(2,zoomRate);
61             renderMap();
62             //zoomRate=zoomRate*2;
63             //div_map.style.zoom=zoomRate;
64             div_miniview.style.width=80*(window.innerWidth/mapWidth)/Math.pow(2,zoomRate)+"px";
65             div_miniview.style.height=60*(window.innerHeight/mapHeight)/Math.pow(2,zoomRate)+"px";
66         }
67         else if(type=="縮小")
68         {
69             zoomRate--;
70             if(zoomRate<-3)
71             {
72                 zoomRate=-3;
73             }
74             div_map.style.zoom=Math.pow(2,zoomRate);
75             renderMap();
76             div_miniview.style.width=80*(window.innerWidth/mapWidth)/Math.pow(2,zoomRate)+"px";
77             div_miniview.style.height=60*(window.innerHeight/mapHeight)/Math.pow(2,zoomRate)+"px";
78             // zoomRate=zoomRate/2;
79             // div_map.style.zoom=zoomRate;
80         }
81     }
View Code

主要是html標簽的樣式操作,

8、渲染回圈

 1 function runOneStep(){//遍歷每個unit并決定它要做的事,runLoop也要呼叫這個方法,暫時把思考、行動、渲染放在同步的幀里,思考頻率、移動速度、單位大小要相互和諧,以正常移動避免碰撞為標準
 2         for(var key in obj_units)//思考
 3         {
 4             var unit=obj_units[key];
 5             if(unit.doing!="dead"&&unit.doing!="unconscious")
 6             {
 7                 unit.think(unit,obj_units,arr_part);
 8             }
 9         }
10         for(var key in obj_units)//行動
11         {
12             var unit=obj_units[key];
13             if(unit.doing!="dead"&&unit.doing!="unconscious")
14             {
15                 unit.do(unit);
16             }
17         }
18         renderMap();//渲染
19     }
20     function runLoop(){
21         flag_autorun=true;
22     }
23     function stopRunLoop(){
24         flag_autorun=false;
25     }
26     var lastframe=new Date().getTime();
27     function Loop()
28     {
29         if(flag_autorun)
30         {
31             runOneStep();
32             var thisframe=new Date().getTime();
33             console.log(thisframe-lastframe,"red:"+obj_owners.red.countAlive,"blue:"+obj_owners.blue.countAlive);
34             lastframe=thisframe;
35         }
36         window.requestAnimationFrame(function(){Loop()});
37     }

事實上可思考的物件存在三個回圈“思考回圈”——比如最小間隔1秒考慮一次接下來做什么,“行動回圈”——比如受到持續傷害時最小間隔0.2秒修改生命值,“渲染回圈”——比如播放60幀每秒的模型影片,這里為了省事把三個回圈合在一起執行,

三、思考

ais.js:

 1 var obj_ais={};//ai串列
 2 obj_ais.近戰戰士=function(unit,obj_units,arr_part){//通過原型方法呼叫,那么這里的this應該是誰??
 3     if(unit.wanting=="lineup")//如果單位現在想列隊,排隊也有兩種思路,一是靠臨近人員自組織,二是獲取所有單位統籌規劃
 4     {//這時應該有一個target引數指明單位要列隊的地點,這個地點應該是隊形中心還是單位的實際點??
 5         //應該在列隊開始時就為每個單位設定精確目標點,還是在運動中實時縮小范圍?還是每個單位都在創建時就分配一個隊伍位置??
 6         var pos_target=unit.target[0];
 7         if(unit2isat(unit,pos_target))
 8         {//如果單位已經到位
 9             unit.wanting="waiting";
10             unit.doing="standing";
11             unit.target=[];
12         }
13         else
14         {
15             unit.doing="walk";
16             if(unit2distance(unit,pos_target)<unit.speed)//如果目標已經在一次思考時間的移動范圍內
17             {
18                 unit.nextpos=pos_target;
19             }
20             else
21             {//計算下一步的位置
22                 unit.nextpos=unit2add(unit2times(unit2normal(unit2substract(unit,pos_target)),unit.speed),unit);
23             }
24         }
25 
26 
27 
28 
29     }
30     if(unit.wanting=="freecharge")      //沖鋒程序中的每次思考都要重新規劃目標
31     {
32         if(!unit.aimAt||unit.aimAt.doing=="dead")//如果還沒有瞄準的目標,或者瞄準的目標已經死亡,則要尋找一個瞄準目標
33         {
34             var arr_res=findNearUnit(arr_part,0,20,"nearest-target-notdead-onlyone",unit.x,unit.y,unit,arr_partowner);//找到了一個目標
35             unit.aimAt=arr_res[0];
36         }
37         if(unit.aimAt)
38         {
39             var dis=unit2distance(unit,unit.aimAt);
40             if(dis<unit.nearAttRange)//如果進入射程
41             {
42                 unit.doing="nearattack"//近戰普通攻擊
43             }
44             else
45             {
46 
47                 if(dis<unit.speed)//如果目標已經在一次思考時間的移動范圍內,移動要留下攻擊目標的半徑
48                 {
49                     unit.doing="chargeattack";//沖鋒攻擊
50                     unit.nextpos=unit2substract(unit2times(unit2normal(unit2substract(unit,unit.aimAt)),unit.aimAt.clipSize/2),unit.aimAt,);
51                 }
52                 else
53                 {
54                     unit.doing="walk";
55                     unit.nextpos=unit2add(unit2times(unit2normal(unit2substract(unit,unit.aimAt)),unit.speed),unit);
56                 }
57             }
58         }
59         else
60         {
61             unit.doing="standing";//如果已經找不到敵人則恢復靜默狀態
62         }
63     }
64 }

這里建立了一個叫做“近戰戰士”的思考方法,接著根據單位wanting屬性的不同為他設定不同的doing、target、nextpos等屬性,

四、行動

dos.js

 1 var obj_dos={}
 2 obj_dos.DOM=function(unit){
 3     if(unit.doing=="walk")
 4     {
 5         unit.left=Math.max(unit.nextpos.left,0);
 6         unit.top=Math.max(unit.nextpos.top,0);
 7 
 8         var x=Math.floor(unit.left/partSizeX);
 9         var y=Math.floor(unit.top/partSizeY);
10         if(x!=unit.x||y!=unit.y)//更新索引位置
11         {
12             unit.x=x;
13             unit.y=y;
14             updatePart(unit,arr_part,arr_partowner);
15         }
16     }
17     else if(unit.doing=="nearattack")
18     {
19         var unitAimAt=unit.aimAt;
20         if(unitAimAt.doing!="dead")
21         {
22             if(unitAimAt.being=="free")
23             {
24                 unitAimAt.being="hp-"+unit.at;
25 
26             }
27             else
28             {
29                 unitAimAt.being+=";hp-"+unit.at;
30             }
31             unitAimAt.hp-=unit.at;
32             if(unitAimAt.hp<1)
33             {
34                 unitAimAt.doing="dead";
35                 obj_owners[unitAimAt.owner.name].countAlive--;
36                 arr_partowner[unitAimAt.x][unitAimAt.y][unitAimAt.owner.name]--;
37             }
38         }
39     }
40     else if(unit.doing=="chargeattack")
41     {
42         unit.left=Math.max(unit.nextpos.left,0);
43         unit.top=Math.max(unit.nextpos.top,0);
44         var x=Math.floor(unit.left/partSizeX);
45         var y=Math.floor(unit.top/partSizeY);
46         if(x!=unit.x||y!=unit.y)//更新索引位置
47         {
48             unit.x=x;
49             unit.y=y;
50             updatePart(unit,arr_part,arr_partowner);
51         }
52 
53         var unitAimAt=unit.aimAt;
54         if(unitAimAt.doing!="dead")
55         {
56             if(unitAimAt.being=="free")
57             {
58                 unitAimAt.being="hp-"+unit.at;
59 
60             }
61             else
62             {
63                 unitAimAt.being+=";hp-"+unit.at;
64             }
65             unitAimAt.hp-=unit.at;
66             if(unitAimAt.hp<1)
67             {
68                 unitAimAt.doing="dead";
69                 obj_owners[unitAimAt.owner.name].countAlive--;
70                 arr_partowner[unitAimAt.x][unitAimAt.y][unitAimAt.owner.name]--;
71             }
72         }
73     }
74 }

根據單位doing屬性的不同,修改單位自身或其他單位的屬性,

五、平面向量計算與快速單位查找

vectorTools.js:

  1 function findNearUnit(arr_part,start,count,type,x,y,unit,arr_partowner)
  2 {//以自身為出發點,尋找附近的單位
  3     var arr_res=[],arr_find1,arr_find2,arr_find3,arr_find4;
  4     if(type=="all")//遍歷所有格找尋所有符合條件的格
  5     {
  6         for (var i = start; i <= count; i++)//x.y相加的總步數,0就是本格
  7         {
  8             for (var xStep1 = 0; xStep1 <= i; xStep1++)
  9             {
 10                 var yStep1 = i - Math.abs(xStep1);
 11                 //var yStep2 = -yStep1;
 12                 //var xStep2 = -xStep1;
 13                 //這里要注意處理陣列為null的情況
 14                 var arr2 = arr_part[x + xStep1];//使用arr_part查找附近單位,避免遍歷所有單位
 15                 arr_find1 = arr2 ? (arr2[y + yStep1]) : null;
 16                 arr_find2 = arr2 ? (arr2[y - yStep1]) : null;
 17                 arr2 = arr_part[x - xStep1];
 18                 arr_find3 = arr2 ? (arr2[y + yStep1]) : null;
 19                 arr_find4 = arr2 ? (arr2[y - yStep1]) : null;
 20                 if(arr_find1)
 21                 {
 22                     arr_res=arr_res.concat(arr_find1);
 23                 }
 24                 if(arr_find2)
 25                 {
 26                     arr_res=arr_res.concat(arr_find2);
 27                 }
 28                 if(arr_find3)
 29                 {
 30                     arr_res=arr_res.concat(arr_find3);
 31                 }
 32                 if(arr_find4)
 33                 {
 34                     arr_res=arr_res.concat(arr_find4);
 35                 }
 36             }
 37         }
 38 
 39     }
 40     else if(type=="nearest"){//從近向遠遍歷,取并列最近的所有格,之后停止遍歷
 41         for (var i = start; i <= count; i++)//x.y相加的總步數,0就是本格
 42         {
 43             for (var xStep1 = 0; xStep1 <= i; xStep1++) {
 44                 var yStep1 = i - Math.abs(xStep1);
 45                 var yStep2 = -yStep1;
 46                 var xStep2 = -xStep1;
 47                 //這里要注意處理陣列為null的情況
 48                 var arr2 = arr_part[x + xStep1];
 49                 arr_find1 = arr2 ? (arr2[y + yStep1]) : null;
 50                 arr_find2 = arr2 ? (arr2[y - yStep1]) : null;
 51                 arr2 = arr_part[x - xStep1];
 52                 arr_find3 = arr2 ? (arr2[y + yStep1]) : null;
 53                 arr_find4 = arr2 ? (arr2[y - yStep1]) : null;
 54                 if(arr_find1)
 55                 {
 56                     arr_res=arr_res.concat(arr_find1);
 57                 }
 58                 if(arr_find2)
 59                 {
 60                     arr_res=arr_res.concat(arr_find2);
 61                 }
 62                 if(arr_find3)
 63                 {
 64                     arr_res=arr_res.concat(arr_find3);
 65                 }
 66                 if(arr_find4)
 67                 {
 68                     arr_res=arr_res.concat(arr_find4);
 69                 }
 70             }
 71             if(arr_res.length>0)
 72             {
 73                 break;
 74             }
 75         }
 76     }
 77     else if(type=="nearest-target-notdead-onlyone")
 78     {//取最近的、屬于規定勢力的、沒有死亡的、只取一個
 79         var arr_res0=[];
 80         var owner_target=unit.target[0];
 81         for (var i = start; i <= count; i++)//x.y相加的總步數,0就是本格
 82         {
 83             for (var xStep1 = 0; xStep1 <= i; xStep1++) {
 84                 var yStep1 = i - Math.abs(xStep1);
 85                 var yStep2 = -yStep1;
 86                 var xStep2 = -xStep1;
 87                 //這里要注意處理陣列為null的情況
 88                 //四個方向隨機選擇
 89                 //這里要避免單位不斷遍歷身邊的大量己方單位!!
 90                 //try catch對性能有額外消耗??!!
 91                 var count2=0;
 92                 // try{
 93                 //     count2+=arr_partowner[x + xStep1][y + yStep1][owner_target]||0;
 94                 // }catch(e){}
 95                 // try{
 96                 //     count2+=arr_partowner[x + xStep1][y - yStep1][owner_target]||0;
 97                 // }catch(e){}
 98                 // try{
 99                 //     count2+=arr_partowner[x - xStep1][y + yStep1][owner_target]||0;
100                 // }catch(e){}
101                 // try{
102                 //     count2+=arr_partowner[x - xStep1][y - yStep1][owner_target]||0;
103                 // }catch(e){}
104                 var arr2=arr_partowner[x + xStep1];
105                 if(arr2)
106                 {
107                     var obj=arr2[y + yStep1];
108                     if(obj)
109                     {
110                         count2+=obj[owner_target]||0;
111                     }
112                     var obj=arr2[y - yStep1];
113                     if(obj)
114                     {
115                         count2+=obj[owner_target]||0;
116                     }
117                 }
118                 var arr2=arr_partowner[x - xStep1];
119                 if(arr2)
120                 {
121                     var obj=arr2[y + yStep1];
122                     if(obj)
123                     {
124                         count2+=obj[owner_target]||0;
125                     }
126                     var obj=arr2[y - yStep1];
127                     if(obj)
128                     {
129                         count2+=obj[owner_target]||0;
130                     }
131                 }
132                 if(count2>0)//如果找到了對應目標的領域,則認為一定能找到一個目標??(活的)!!
133                 {
134                     var arr2 = arr_part[x + xStep1];
135                     arr_find1 = arr2 ? (arr2[y + yStep1]) : [];
136                     arr_find2 = arr2 ? (arr2[y - yStep1]) : [];
137                     arr2 = arr_part[x - xStep1];
138                     arr_find3 = arr2 ? (arr2[y + yStep1]) : [];
139                     arr_find4 = arr2 ? (arr2[y - yStep1]) : [];
140                     if(arr_find1)
141                     {
142                         arr_res0=arr_res0.concat(arr_find1);
143                     }
144                     if(arr_find2)
145                     {
146                         arr_res0=arr_res0.concat(arr_find2);
147                     }
148                     if(arr_find3)
149                     {
150                         arr_res0=arr_res0.concat(arr_find3);
151                     }
152                     if(arr_find4)
153                     {
154                         arr_res0=arr_res0.concat(arr_find4);
155                     }
156                     var len2=arr_res0.length;
157                     var nearestUnit=null;
158                     for(var j=0;j<len2;j++)
159                     {
160 
161                         var obj=arr_res0[j];
162                         if(obj.doing!="dead"&&obj.owner.name==owner_target)
163                         {
164 
165                             if(!nearestUnit)
166                             {
167                                 nearestUnit=obj;
168                             }
169                             else
170                             {
171                                 if(unit2distance(obj,unit)<unit2distance(nearestUnit,unit)){
172                                     nearestUnit=obj;
173                                 }
174                             }
175                         }
176                     }
177                     if(nearestUnit)
178                     {
179                         arr_res.push(nearestUnit);
180                     }
181 
182                 }
183             }
184             if(arr_res.length>0)
185             {
186                 //arr_res=[arr_res[newland.RandomChooseFromArray(arr_res)]];
187                 break;
188             }
189         }
190     }
191     return arr_res;
192 }//分隔線
193 function unit2distance(unit1,unit2)//兩點間距離
194 {
195     return Math.pow(Math.pow((unit1.left-unit2.left),2)+Math.pow((unit1.top-unit2.top),2),0.5)
196 }
197 function unit2isat(unit,pos)
198 {
199     if(unit.left==pos.left&&unit.top==pos.top)//如果單位正好處于這個位置
200     {
201         return true;
202     }
203     else
204     {
205         return false;
206     }
207 }
208 function unit2substract(posFrom,posTo)//取兩個二元向量的差向量
209 {
210     var posRes={left:posTo.left-posFrom.left,top:posTo.top-posFrom.top};
211     return posRes;
212 }
213 function unit2normal(unit)//標準化二元向量
214 {
215     var length=Math.pow(unit.left*unit.left+unit.top*unit.top,0.5);
216     var posRes={left:unit.left/length,top:unit.top/length};
217     return posRes;
218 }
219 function unit2times(unit,times)//二元向量伸縮
220 {
221     var posRes={left:unit.left*times,top:unit.top*times};
222     return posRes;
223 }
224 function unit2add(unit1,unit2)
225 {
226     var posRes={left:unit1.left+unit2.left,top:unit1.top+unit2.top};
227     return posRes;
228 }
229 function isTooNear(unit,arr,dis)//unit與arr中的物件是否過于接近,只要有一個就回傳true
230 {
231     var len=arr.length;
232     if(!dis)//如果沒有規定統一的最近距離,
233     {
234         for(var i=0;i<len;i++)
235         {
236             var obj=arr[i]
237             if(unit2distance(unit,obj)<(unit.clipSize+obj.clipSize)/2)
238             {
239                 return true;
240             }
241         }
242     }
243     else
244     {
245         for(var i=0;i<len;i++)
246         {
247             var obj=arr[i]
248             if(unit2distance(unit,obj)<dis)
249             {
250                 return true;
251             }
252         }
253     }
254 
255 }//分隔線
256 function updatePart(unit,arr_part,arr_partowner){//更新兩個索引陣列
257     var x=unit.x;
258     var y=unit.y;
259     var arr_old=arr_part[x][y];
260     var len=arr_old.length;
261     for(var i=0;i<len;i++)
262     {
263         if(arr_old[i].id==unit.id)
264         {
265             arr_old.splice(i,1);
266             arr_partowner[x][y][unit.owner.name]--;
267             break;
268         }
269     }
270     if(!arr_part[x])
271     {
272         arr_part[x]=[];
273     }
274     if(!arr_part[x][y])
275     {
276         arr_part[x][y]=[];
277     }
278     arr_part[x][y].push(unit);
279     if(!arr_partowner[x])
280     {
281         arr_partowner[x]=[];
282     }
283     if(!arr_partowner[x][y])
284     {
285         arr_partowner[x][y]={};
286     }
287     var obj_temp=arr_partowner[x][y];
288     if(!obj_temp[unit.owner.name])
289     {
290         obj_temp[unit.owner.name]=1;
291     }
292     else
293     {
294         obj_temp[unit.owner.name]++;
295     }
296 }

六、總結

以上完成了一個最基礎的多單位思考與互動框架,在此基礎上可以編輯更多種類的單位和更復雜思考方式,但框架尚存在問題,比如缺少單位間碰撞檢測(或多層堆疊限制),這會導致所有單位最終重疊為一點,比如視角控制方式不流暢,比如三個回圈未分離等等,

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/251558.html

標籤:JavaScript

上一篇:溫習資料演算法—貪吃蛇

下一篇:Electron實用技巧-開機啟動時隱藏主視窗,只顯示系統托盤

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more