2022年8月31日 星期三

DOM - 2 Event 的特殊處理 - 停止event預設動作 - 停止往上冒泡 -bubble,catch

目的: 停止event預設動作 - 停止往上冒泡處理說明:1> Label 的event flow 為 bubble 方式時

            2> 觸發 lbl.onclick event後 , console 顯示 "lbl click"

                 瀏覽器將 click event  自動往下傳, 即傳給 checkbox.click event

            3> 因 checkbox event 為 bubble 方式,所以又往上傳給 lbl 

                即觸發 lbl.onclick event , concole 又顯示 "lbl click"

--> 即 lbl.onclick event 被觸發兩次


一.要阻擋事件向上冒泡傳遞:

--> event.stopPropagation()



<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="src/style.css" />
  </head>
  <body>
    <h1>Hi friend, try edit me!</h1>
    <label class="lbl">
      Label <input type="checkbox" name="chkbox" id="chkbox" />
    </label>
    // label

    <script>
      var lbl = document.querySelector('.lbl');
      var chkbox = document.querySelector('#chkbox');

      lbl.addEventListener('click', function (e) {
        console.log('lbl click');
      }, false);

      chkbox.addEventListener('click', function (e) {
        console.log('chkbox click');
      }, false);

    </script>

    <script src="src/script.js"></script>
  </body>
</html>

-->

     chkbox.addEventListener('click', function (e) {
        console.log('chkbox click');
         e.stopPropagation();
      }, false);





二.不執行預設動作, 只執行目前動作( console.log("google") )



<a id="link" href="https://www.google.com">Google</a>

var link = document.querySelector('#link'); 

// 在 evend handler 加上 e.preventDefault(); 
link.addEventListener('click', function (e) { 
e.preventDefault(); 
console.log('Google!'); 
}, false);

Browser - 三大元素 HTML / CSS / JavaScript

目的: 認識 Browser 的三大要素 

處理說明:「HTML、CSS 與 JavaScript 是網頁前端三大要素」:
  1. HTML 負責資料與結構
  2. CSS 負責樣式與呈現
  3. JavaScript 負責行為與互動
原始參考網址 : https://ithelp.ithome.com.tw/articles/10191666

  • JavaScript 核心 (以 ECMAScript 標準為基礎)
  • BOM (Browser Object Model,瀏覽器物件模型)
  • DOM (Document Object Model,文件物件模型)
由於「BOM」與「DOM」是由瀏覽器執行環境所提供。
換句話說,在 node 環境下的 JavaScript 就不會有這兩個部分

1>BOM (Browser Object Model,瀏覽器物件模型),是瀏覽器所有功能的核心,與網頁的內容無關。
 W3C 把各家瀏覽器都有實作的部分,以及確定已經(或未來會) 加入的功能,統一集合起來納入了 HTML5 的標準中,這也就是我們現在看到的 BOM API 的實作。


1>BOM 的核心是 window 物件。
而 window 物件提供的屬性主要為 documentlocationnavigatorscreenhistory 以及 frames
window 物件 - 用來與瀏覽器溝通的窗口」

alert("message");
=window.alert(message);
一行程式碼就可以生成一個對話框,很神奇吧?
而這就是瀏覽器環境的 BOM 提供給 JavaScript 控制的功能之一。
類似的對話框還有用來提供「確定/取消」的 window.confirm() window.confirm ,以及開放式問答的 window.prompt() window.prompt 對話框。
當然 BOM 提供的 API 很多,包含開啟/關閉視窗,改變視窗大小,計時器與取得網址等等。 這些在之後的文章當中還會再詳細解說。

2>DOM (Document Object Model,文件物件模型),是一個將 HTML 文件以樹狀的結構來表示的模型,而組合起來的樹狀圖,我們稱之為「DOM Tree」


DOM 的 document 其實也是 window 物件的子物件之一。

而「DOM」 與「BOM」最大的區別在於:

  • BOM: JavaScript 與「瀏覽器」溝通的窗口,不涉及網頁內容。
DOM: JavaScript 用來控制「網頁」的節點與內容的標

「BOM」完全依賴於瀏覽器廠商實作本身無標準規範,
「DOM」有著 W3C 所制定的標準來規範。


Ex:
<h1 id="greet"></h1>
<script> document.querySelector('#greet').textContent = 'Hello World!' </script>

--> 透過 document.querySelector() 方法來取得節點,
      然後修改 textContent 屬性

2022年8月30日 星期二

DOM -0 DOM解析 - How Browser Work

目的: DOM的解析及取得元件

處理說明:  1> Browser 如何解析 HTML 成 DOM


原始參考網址 : https://ithelp.ithome.com.tw/articles/10191765

透過 DOM API 查找節點







當一個網頁被載入到瀏覽器時,瀏覽器會先分析這個 HTML 檔案,然後會依照這份 HTML 的內容解析成「DOM」 (Document Object Model,文件物件模型)

DOM 是 W3C 制定的一個規範,它是獨立於平台與語言的標準。 換言之,只要遵守這樣的規範實作,不管是什麼平台或者是什麼語言開發,都可以透過 DOM 提供的 API 來操作 DOM 的內容、結構與樣式。

所以說,DOM 是網頁的根本,懂得 控制籃板球的人就能控制整場比賽 控制 DOM 就可以控制整個網頁,做出良好的互動體驗

那麼在今天的分享中,我們就繼續來介紹 DOM API 查找節點的方法吧。

1><script> </script>放在 </body>之前 , HELLO 正常顯示

-->
當我們把 <script> 標籤放在 </body> 結束之前,
由於 DOM 已經解析完成所以 document.querySelector 就可以順利取得 id="hello" 的節點,並且把 'HELLO' 的字串放在網頁裡囉!



2><script> </script>放在 </head>之前 , HELLO 無法正常顯示

-->

當瀏覽器在 <head> ... </head> 之間遇到 <script> 標籤時,就會暫停解析網頁,並且「立即」執行 <script> 裡的內容,直到 script 執行完畢後再繼續解析網頁。發在 <head> ... </head> 裡的 <script> 想要嘗試去尋找 <div id="hello"> 這個標籤,但因為還沒解析到網頁本體,所以也無從取得


document 物件是 「DOM tree」 的根節點,所以當我們要存取 HTML 時,都從 document 物件開始。 而 DOM 的節點類型除了 「HTML 元素節點」 (element nodes) 外,還有「文字節點」 (text nodes)、「註解節點」 (comment nodes) 等。

// 針對給定的 Selector 條件,回傳第一個 或 所有符合條件的 NodeList。
document.querySelector('xxx'); 
document.querySelectorAll('xxx');

document.querySelector 與 document.querySelectorAll 可以用 「CSS 選擇器」 (CSS Selectors) 來取得「第一個」或「所有」符合條件的元素集合 (NodeList)。



document.getElementById 以及 document.querySelector 
-->因爲取得的一定只有一個元素/節點,所以不會有 index 與 length 屬性。

而 document.getElementsBy** (注意,有個 s) 以及 document.querySelectorAll 
-->分別回傳 「HTMLCollection」 與 「NodeList」
「HTMLCollection」只收集 HTML element 節點
「NodeList」除了 HTML element 節點,也包含文字節點、屬性節點等



DOM -1 Event 的處理機制 - bubble -catch -eventflow

目的: 了解 Web  DOM的 event 處理 機制

處理說明:   1> catch 時, 由上而下 (Document --> html --> body --> table --> tr --> td --> div)

                    2> bubble時, 由下而上(div-->td--> tr--> table --> body --> html --> Document)

-->  DOM 兩種機制 (catch/bubble) 均有, 可分別設定 catch / bubble 的 event handler

參考原始網址: https://ithelp.ithome.com.tw/articles/10191970

- 重新認識 JavaScript: Day 14 事件機制的原理



而事件流程 (Event Flow) 指的就是「網頁元素接收事件的順序」。

事件流程可以分成兩種機制:

  • 事件冒泡 (Event Bubbling)
  • 事件捕獲 (Event Capturing)

假設現在的事件是點擊上圖中藍色的 <td>

那麼當 td 的 click 事件發生時,會先走紅色的 「capture phase」:

  1. Document
  2. <html>
  3. <body>
  4. <table>
  5. <tbody>
  6. <tr>
  7. <td> (實際被點擊的元素)

由上而下依序觸發它們的 click 事件。

然後再繼續執行綠色的 「bubble phase」,反方向由 <td> 一路往上傳至 Document,整個事件流程到此結束。

Ex:  DOM的實作案例

<div>
    <div id="parent">父元素      
          <div id="child">子元素</div>
     </div>
</div>


// 父元素
var parent = document.getElementById('parent');
// 子元素
var child = document.getElementById('child');

// 透過 addEventListener 指定事件的綁定
// 第三個參數 true / false 分別代表捕獲/ 冒泡 機制

parent.addEventListener('click', function () {
  console.log('Parent Capturing');
}, true);  //capture 機制 event hadler

parent.addEventListener('click', function () {
  console.log('Parent Bubbling');
}, false); //bubble 機制 event hadler


child.addEventListener('click', function () {
  console.log('Child Capturing');
}, true);

child.addEventListener('click', function () {
  console.log('Child Bubbling');
}, false);

-->

當我點擊的是「子元素」的時候,透過 console.log 可以觀察到事件觸發的順序為:
       "Parent Capturing"
       "Child Capturing"
       "Child Bubbling"
       "Parent Bubbling"

由此可知,點擊子元素的時候,父層的 Capturing 會先被觸發,然後再到子層內部的 Capturing 或 Bubbling 事件。 最後才又回到父層的 Bubbling 結束。

子層的 Capturing 或 Bubbling 誰先誰後呢?
要看你程式碼的順序而定。

子層若是 Capturing 在 Bubbling 前面:

child.addEventListener('click', function () { console.log('Child Capturing'); }, true); child.addEventListener('click', function () { console.log('Child Bubbling'); }, false);

--> 子層觸發順序
"Child Capturing" "Child Bubbling"

-->
addEventListener() 基本上有三個參數,分別是「事件名稱」、「事件的處理器」(事件觸發時執行的 function),以及一個「Boolean」值,由這個 Boolean 決定事件是以「捕獲」或「冒泡」機制執行,若不指定則預設為「冒泡」。
true/false : catch/bubble


Bubble 及 Catch event flow





[修改]鈕.click 時 , parent & child click程式的執行順序

 目的:  [修改]鈕.click 時 , parent  &  child  click程式的執行順序

處理說明:  1>先執行  parent 的程式, 再執行 child 的程式

                   2>如何 disable parent 的程式 



V20306 - RadioGroup 存回資料庫 - 欄位值取得MAX+1

 目的: 編輯畫面 RadioGroup 欄位存回資料庫, PK=MAX(PK)+1

處理說明:  1> PK=MAX(PK)+1
  1>>*.js   np["ASPNO"] = "ASP" + DatetoStr(now, "Ymd");
  2>>*.cs   Tmp_NEXT_ASPNO = Tmp_ASPNO + (int.Parse(Tmp_MAX_ASPNO.Substring(11, 3))+1).ToString("000");
  
                 2> RadioGroup欄位值
1>>每一Radio.id均不同, 傳回後端每一Radio均有一值(true/false)
2>>RadioGroup欄位值由 np["STAT"]=Ext.getCmp("name").getValue(); 取得送至後端



1>*.js  - 設定  PK=MAX(PK)+1

var buttonModel = Ext.create('G_buttonModel');        

//存檔時,自動設定欄位值 : PK,
Ext.getCmp('btn_save').setFormValue = function () {
       //1>取得 PK= MAX(PK)+1 , 新增時,才設定 PK 欄位值, 編輯時 , 不設定欄位值
        var modelType = buttonModel.getModelType();
         if (!(modelType == 1))
             return true;
        var Tmp_NEXT_ASPNO = get_NEXT_ASPNO();
        Ext.getCmp("ASPNO").setValue(Tmp_NEXT_ASPNO);

        //2>設定 RadioGroup 欄位值 , 由 S_DB.add_np 設定特別的欄位值
        S_DB.add_np = {};
        S_DB.add_np["WTLV"] = Ext.getCmp("WTLV").getValue();
        S_DB.add_np["ITPR"] = Ext.getCmp("ITPR").getValue();
return true;
}

var np=s_JSON('myform');
--> Template 先執行 setFormValue() , 再執行  np 取欄位值,
      所以  setFormValue() 的欄位值, 會存入 np 參數



2>*.cs

1>>取得 MAX(PK)+1
[HttpPost]
        public HttpResponseMessage GET_NEXT_ASPNO()
        {
            var c = HttpContext.Current;
            NameValueCollection nvc = c.Request.Form;
            var response = this.Request.CreateResponse();
            string Tmp_ASPNO = nvc["ASPNO"];
            string Tmp_Str = "";            

            OracleConnection conn = new OracleConnection(DBService.ConnectionString(DBLINK));//
            OracleCommand cmd = new OracleCommand();
            OracleDataReader reader;

            conn.Open();
            conn.ClientInfo = User.Identity.Name;
            conn.ModuleName = BaseSYS + "_" + BaseMODID;
            conn.ActionName = ActionName;
            cmd.Connection = conn;
            string Tmp_MAX_ASPNO = "", Tmp_NEXT_ASPNO = "";
            try
            {
                string Tmp_Sql = "  SELECT MAX(ASPNO)  as MAX_ASPNO "
                                           + "  FROM   AMM_ASP "
                                           + "  WHERE ASPNO   LIKE  " + myfunc.AA(Tmp_ASPNO+"%");
                cmd.CommandText = Tmp_Sql;
                reader = cmd.ExecuteReader();
                if (reader.Read())
                {
                    Tmp_MAX_ASPNO = reader["MAX_ASPNO"].ToString();
                    if (myfunc.checkisnull(Tmp_MAX_ASPNO))
                        Tmp_NEXT_ASPNO = Tmp_ASPNO + "001";
                    else
                    {
                        Tmp_NEXT_ASPNO = Tmp_ASPNO + (int.Parse(Tmp_MAX_ASPNO.Substring(11, 3))+1).ToString("000");
                    }
                }
                Tmp_Str = "{success: true ,  NEXT_ASPNO:" + myfunc.AA(Tmp_NEXT_ASPNO) + ","
                                            + " }";

                response.Content = new StringContent(Tmp_Str);    // 回應內容
                return response;
            }// end of try
            catch (Exception e)
            {
                Tmp_Str = "{success: false ,  NEXT_ASPNO:" + myfunc.AA(Tmp_NEXT_ASPNO) + ","
                                            + " }";
                response.Content = new StringContent(Tmp_Str);    // 回應內容
                return response;
            }
            finally
            {
                conn.Close();
            }
        }  // end of get_NEXT_ASPNO


//移除 nvc 由 RadioGroup 的每一Radio欄位值(true/false)
2>>
[HttpPost]
        public void Insert()
        {
            var c = System.Web.HttpContext.Current;
            NameValueCollection nvc = c.Request.Form;
            NameValueCollection nvc1= new NameValueCollection();
            //nvc 移除 radio開頭的 key , 以免加入 Insert Sql
            var Tmp_key = "";
            foreach(string key in nvc.Keys)
            {
                if (!key.Contains("radio"))
                    nvc1[key] = nvc[key];
            }
            excuteInsert(nvc1, DBTable);
        }

2022年8月29日 星期一

V20306 - css 的應用

 目的:  *.CSS檔案放置目錄及 CSS class

處理說明: 1> *.css 檔案放置在 Content 子目錄

                  2> css class 定義字型大小,顏色,寬度,長度