整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          HTML DOM 事件

          HTML DOM 事件

          HTML DOM 事件允許Javascript在HTML文檔元素中注冊不同事件處理程序。

          事件通常與函數結合使用,函數不會在事件發生前被執行! (如用戶點擊按鈕)。

          提示: 在 W3C 2 級 DOM 事件中規范了事件模型。

          HTML DOM 事件

          DOM: 指明使用的 DOM 屬性級別。

          鼠標事件

          屬性描述DOM
          onclick當用戶點擊某個對象時調用的事件句柄。2
          oncontextmenu在用戶點擊鼠標右鍵打開上下文菜單時觸發
          ondblclick當用戶雙擊某個對象時調用的事件句柄。2
          onmousedown鼠標按鈕被按下。2
          onmouseenter當鼠標指針移動到元素上時觸發。2
          onmouseleave當鼠標指針移出元素時觸發2
          onmousemove鼠標被移動。2
          onmouseover鼠標移到某元素之上。2
          onmouseout鼠標從某元素移開。2
          onmouseup鼠標按鍵被松開。2

          鍵盤事件

          屬性描述DOM
          onkeydown某個鍵盤按鍵被按下。2
          onkeypress某個鍵盤按鍵被按下并松開。2
          onkeyup某個鍵盤按鍵被松開。2

          框架/對象(Frame/Object)事件

          屬性描述DOM
          onabort圖像的加載被中斷。 ( <object>)2
          onbeforeunload該事件在即將離開頁面(刷新或關閉)時觸發2
          onerror在加載文檔或圖像時發生錯誤。 ( <object>, <body>和 <frameset>)
          onhashchange該事件在當前 URL 的錨部分發生修改時觸發。
          onload一張頁面或一幅圖像完成加載。2
          onpageshow該事件在用戶訪問頁面時觸發
          onpagehide該事件在用戶離開當前網頁跳轉到另外一個頁面時觸發
          onresize窗口或框架被重新調整大小。2
          onscroll當文檔被滾動時發生的事件。2
          onunload用戶退出頁面。 ( <body> 和 <frameset>)2

          表單事件

          屬性描述DOM
          onblur元素失去焦點時觸發2
          onchange該事件在表單元素的內容改變時觸發( <input>, <keygen>, <select>, 和 <textarea>)2
          onfocus元素獲取焦點時觸發2
          onfocusin元素即將獲取焦點時觸發2
          onfocusout元素即將失去焦點時觸發2
          oninput元素獲取用戶輸入時觸發3
          onreset表單重置時觸發2
          onsearch用戶向搜索域輸入文本時觸發 ( <input="search">)
          onselect用戶選取文本時觸發 ( <input> 和 <textarea>)2
          onsubmit表單提交時觸發2

          剪貼板事件

          屬性描述DOM
          oncopy該事件在用戶拷貝元素內容時觸發
          oncut該事件在用戶剪切元素內容時觸發
          onpaste該事件在用戶粘貼元素內容時觸發

          打印事件

          屬性描述DOM
          onafterprint該事件在頁面已經開始打印,或者打印窗口已經關閉時觸發
          onbeforeprint該事件在頁面即將開始打印時觸發

          拖動事件

          事件描述DOM
          ondrag該事件在元素正在拖動時觸發
          ondragend該事件在用戶完成元素的拖動時觸發
          ondragenter該事件在拖動的元素進入放置目標時觸發
          ondragleave該事件在拖動元素離開放置目標時觸發
          ondragover該事件在拖動元素在放置目標上時觸發
          ondragstart該事件在用戶開始拖動元素時觸發
          ondrop該事件在拖動元素放置在目標區域時觸發

          多媒體(Media)事件

          事件描述DOM
          onabort事件在視頻/音頻(audio/video)終止加載時觸發。
          oncanplay事件在用戶可以開始播放視頻/音頻(audio/video)時觸發。
          oncanplaythrough事件在視頻/音頻(audio/video)可以正常播放且無需停頓和緩沖時觸發。
          ondurationchange事件在視頻/音頻(audio/video)的時長發生變化時觸發。
          onemptied當期播放列表為空時觸發
          onended事件在視頻/音頻(audio/video)播放結束時觸發。
          onerror事件在視頻/音頻(audio/video)數據加載期間發生錯誤時觸發。
          onloadeddata事件在瀏覽器加載視頻/音頻(audio/video)當前幀時觸發觸發。
          onloadedmetadata事件在指定視頻/音頻(audio/video)的元數據加載后觸發。
          onloadstart事件在瀏覽器開始尋找指定視頻/音頻(audio/video)觸發。
          onpause事件在視頻/音頻(audio/video)暫停時觸發。
          onplay事件在視頻/音頻(audio/video)開始播放時觸發。
          onplaying事件在視頻/音頻(audio/video)暫停或者在緩沖后準備重新開始播放時觸發。
          onprogress事件在瀏覽器下載指定的視頻/音頻(audio/video)時觸發。
          onratechange事件在視頻/音頻(audio/video)的播放速度發送改變時觸發。
          onseeked事件在用戶重新定位視頻/音頻(audio/video)的播放位置后觸發。
          onseeking事件在用戶開始重新定位視頻/音頻(audio/video)時觸發。
          onstalled事件在瀏覽器獲取媒體數據,但媒體數據不可用時觸發。
          onsuspend事件在瀏覽器讀取媒體數據中止時觸發。
          ontimeupdate事件在當前的播放位置發送改變時觸發。
          onvolumechange事件在音量發生改變時觸發。
          onwaiting事件在視頻由于要播放下一幀而需要緩沖時觸發。

          動畫事件

          事件描述DOM
          animationend該事件在 CSS 動畫結束播放時觸發
          animationiteration該事件在 CSS 動畫重復播放時觸發
          animationstart該事件在 CSS 動畫開始播放時觸發

          過渡事件

          事件描述DOM
          transitionend該事件在 CSS 完成過渡后觸發。

          其他事件

          事件描述DOM
          onmessage該事件通過或者從對象(WebSocket, Web Worker, Event Source 或者子 frame 或父窗口)接收到消息時觸發
          onmousewheel已廢棄。 使用 onwheel 事件替代
          ononline該事件在瀏覽器開始在線工作時觸發。
          onoffline該事件在瀏覽器開始離線工作時觸發。
          onpopstate該事件在窗口的瀏覽歷史(history 對象)發生改變時觸發。
          onshow該事件當 <menu> 元素在上下文菜單顯示時觸發
          onstorage該事件在 Web Storage(HTML 5 Web 存儲)更新時觸發
          ontoggle該事件在用戶打開或關閉 <details> 元素時觸發
          onwheel該事件在鼠標滾輪在元素上下滾動時觸發

          事件對象

          常量

          靜態變量描述DOM
          CAPTURING-PHASE當前事件階段為捕獲階段(3)1
          AT-TARGET當前事件是目標階段,在評估目標事件(1)2
          BUBBLING-PHASE當前的事件為冒泡階段 (2)3

          屬性

          屬性描述DOM
          bubbles返回布爾值,指示事件是否是起泡事件類型。2
          cancelable返回布爾值,指示事件是否可擁可取消的默認動作。2
          currentTarget返回其事件監聽器觸發該事件的元素。2
          eventPhase返回事件傳播的當前階段。2
          target返回觸發此事件的元素(事件的目標節點)。2
          timeStamp返回事件生成的日期和時間。2
          type返回當前 Event 對象表示的事件的名稱。2

          方法

          方法描述DOM
          initEvent()初始化新創建的 Event 對象的屬性。2
          preventDefault()通知瀏覽器不要執行與事件關聯的默認動作。2
          stopPropagation()不再派發事件。2

          目標事件對象

          方法

          方法描述DOM
          addEventListener()允許在目標事件中注冊監聽事件(IE8 = attachEvent())2
          dispatchEvent()允許發送事件到監聽器上 (IE8 = fireEvent())2
          removeEventListener()運行一次注冊在事件目標上的監聽事件(IE8 = detachEvent())2

          事件監聽對象

          方法

          方法描述DOM
          handleEvent()把任意對象注冊為事件處理程序2

          文檔事件對象

          方法

          方法描述DOM
          createEvent()2

          鼠標/鍵盤事件對象

          屬性

          屬性描述DOM
          altKey返回當事件被觸發時,"ALT" 是否被按下。2
          button返回當事件被觸發時,哪個鼠標按鈕被點擊。2
          clientX返回當事件被觸發時,鼠標指針的水平坐標。2
          clientY返回當事件被觸發時,鼠標指針的垂直坐標。2
          ctrlKey返回當事件被觸發時,"CTRL" 鍵是否被按下。2
          Location返回按鍵在設備上的位置3
          charCode返回onkeypress事件觸發鍵值的字母代碼。2
          key在按下按鍵時返回按鍵的標識符。3
          keyCode返回onkeypress事件觸發的鍵的值的字符代碼,或者 onkeydown 或 onkeyup 事件的鍵的代碼。2
          which返回onkeypress事件觸發的鍵的值的字符代碼,或者 onkeydown 或 onkeyup 事件的鍵的代碼。2
          metaKey返回當事件被觸發時,"meta" 鍵是否被按下。2
          relatedTarget返回與事件的目標節點相關的節點。2
          screenX返回當某個事件被觸發時,鼠標指針的水平坐標。2
          screenY返回當某個事件被觸發時,鼠標指針的垂直坐標。2
          shiftKey返回當事件被觸發時,"SHIFT" 鍵是否被按下。2

          方法

          方法描述W3C
          initMouseEvent()初始化鼠標事件對象的值2
          initKeyboardEvent()初始化鍵盤事件對象的值3

          如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!

          :html編碼
          背景:html編碼是用于輸出html原本的標簽的


          想在頁面上輸出div標簽,但是如果我在html標簽里直接寫的話,就會被當成div標簽執行,并不會輸出在頁面上,這個時候我想將他輸出在頁面上就需要用html編碼

          XSS中的應用:這種編碼的形式可以用來去繞過一些過濾,比如,有些會過濾掉script ,alert,< >這樣的危險的符號,這個時候,就可以用Html編碼來繞開過濾


          比如這里的輸出點在scr里,可以閉合雙引號,然后寫一個onerror事件,將alert(1)進行html十進制編碼,這樣就避開了輸入的過濾,當數據到達輸出點時,頁面會先解碼,這個時候onerror后面就變成了字符串alert(1),但是當圖片資源加載失敗,觸發onerror這個事件時,這個時候這個字符串alert(1),就會當作js代碼執行,就會彈窗。我這里用的html的十進制編碼,用十六進制也是一樣的效果

          Html在線編碼工具:https://www.qqxiuzi.cn/bianma/zifushiti.php

          二:js編碼

          XSS應用:一般js的編碼用在通過innerHTML輸出在html里面,比如var search = “可控點”;

          document.getElementById().innerHTML=search;

          在script標簽中,先將js編碼解碼,變成字符串<img src=“x” οnerrοr=alert(1)>,,然后就會以字符串的形式輸出在html的div標簽里,然后當作html代碼執行,也就執行了這個語句,成功彈窗

          Js解碼是用的xss encode插件

          三:url編碼

          背景:http協議中傳輸參數是key=value這種鍵值對的形式存在的,如果需要傳多個參數,就需要用&進行分割,如name1=value1&name=value2&name3=value3這種形式,如果這個時候,我們的值里包含了&或者=這樣的符號,比如name1=value1,其中,value1的值是aaa&b=cc,那么輸出的時候就會變成這樣:name1=aaa&b=cc,這本來是一個鍵值對,但是服務器會解析成兩個,會造成歧義,為了避免這種情況,對參數進行了url編碼。&:%26,=:%3D,編碼后就變成了name1=aaa%26b%3Dcc,這樣服務器解析時,就還是一個鍵值對,然后進行Url解碼,就會獲取到正確的值了。

          XSS中的應用:比如說當你的輸出點在a標簽的href屬性中時,對:進行了過濾,這個你輸javascript:alert(1)時,:就會被過濾,導致不能執行,這個時候就可以先用html編碼成:,再

          用url編碼將&編碼成%26,再輸出點瀏覽器會將html編碼解碼回:,然后輸出在href里,就可以成功彈窗

          url編碼和解碼可以在js控制臺使用js語句來進行編碼解碼:encodeURI(),encodeURIcomponed()

          也可以用在線編碼工具:http://tool.chinaz.com/tools/urlencode.aspx

          四:base64編碼

          Base64一般用在a標簽和iframe標簽中,

          <a href="輸出點">

          </a> <iframe src="輸出點" frameborder="0"></iframe>,

          如果過濾了javascript<>”’時,就可以考慮base64編碼,用data協議

          <a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==">test</a>

          解碼后為:<img src=x οnerrοr=alert(1)>

          當點擊鏈接時,頁面就會以html的方式解析,用base64的方法解碼,然后成功結果彈窗。

          Base64在線編碼工具:https://base64.us/

          注:文章轉自互聯網

          源:https://www.cnblogs.com/ITPower/p/14737901.html

          vuex官網: https://vuex.vuejs.org/zh/

          一. 前言

          不管是Vue,還是 React,都需要管理狀態(state),比如組件之間都有共享狀態的需要。
          什么是共享狀態? 比如一個組件需要使用另一個組件的狀態,或者一個組件需要改變另一個組件的狀態,都是共享狀態。

          如果不對狀態進行有效的管理,狀態在什么時候,由于什么原因,如何變化就會不受控制,就很難跟蹤和測試了。

          在軟件開發里,有些通用的思想,比如隔離變化,約定優于配置等,隔離變化就是說做好抽象,把一些容易變化的地方找到共性,隔離出來,不要去影響其他的代碼。約定優于配置就是很多東西我們不一定要寫一大堆的配置,比如我們幾個人約定,view 文件夾里只能放視圖,不能放過濾器,過濾器必須放到 filter 文件夾里,那這就是一種約定,約定好之后,我們就不用寫一大堆配置文件了,我們要找所有的視圖,直接從 view 文件夾里找就行。

          根據這些思想,對于狀態管理的解決思路就是:把組件之間需要共享的狀態抽取出來,遵循特定的約定,統一來管理,讓狀態的變化可以預測。

          二.什么是Vuex

          Vuex是一個專門為Vue.js應用程序開發做狀態管理的.

          他采用
          集中式存儲管理應用的所有組件的狀態, 并以響應的規則保證狀態以一種可預測的方式發生變化.

          1. 什么是狀態管理呢?

          vuex官網說到的"狀態管理模式", "集中式存儲管理", 這些詞和"狀態管理"都是一個含義. 就是管理狀態.

          我們通常會有很多組件, 組件之間可能會共享狀態. 那么如何定義這個狀態呢? 定義在某一個組件里面肯定是不合適的, 要定義在最外層.

          用vue生態圈來說, 有多個組件要共享狀態, 通常狀態我們用變量來表示, 也就是多個組件之間共享變量. 當共享變量變多, 我們就是用一個對象來存儲, 這個對象就是存儲共享狀態的對象. 通常, 這個對象放在vue頂層的實例中. 其他各個組件都可以使用.

          而vue是響應式編程方式, 一個組件修改了狀態, 其他組件能夠實時響應么?這就是Vuex實現的功能.他的主要功能:

          管理狀態: 因為是將各種狀態保存在一個地方, 所以也叫集中式存儲管理 或者 集中式裝填管理響應式: 一個組件修改了狀態, 其他組件能夠實時響應

          2. 通常什么狀態需要放在Vuex中管理呢?

          不是所有的狀態都要交給vuex來管理的, 只有在多界面之間共享的狀態, 我們才將其交給vuex來管理. 比如:

          • 用戶登錄狀態: 用戶名, 頭像, 昵稱等等. 很多頁面可能都會用到用戶的基本信息, 像這些統一的信息, 我們就可以放在統一的地方進行管理了.
          • token: 用戶登錄的令牌, 某些接口必須有令牌才能訪問, 那么這些幾口就需要共享token
          • 商品收藏, 購物車中的物品等. 我們在各個界面都可以添加商品搜藏, 都可以加購, 這時候, 就可以將其放入到vuex里面

          放在vuex中, 不僅能夠共享狀態, 還能夠實時響應.

          3. Vuex的設計思想

          Vuex 全局維護著一個對象,使用到了單例設計模式。在這個全局對象中,所有屬性都是響應式的,任意屬性進行了改變,都會造成使用到該屬性的組件進行更新。并且只能通過 commit 的方式改變狀態,實現了單向數據流模式。

          Vuex集成到了Vue的官方調試工具devtools extension, 提供了諸如零配置time-travel調試,狀態快照導入導出等高級調試功能.

          三. Vuex是如何在多組件間進行狀態管理的?

          2.1. 單界面狀態管理

          之前我們遇到的都是在單界面進行狀態管理. 單界面的狀態管理有3個部分, 如下圖所示:

          第一部分: state
          第二部分: view
          第三部分: action

          三部分是如何工作的呢? 通常狀態我們會用一個變量來表示, 定義在組件的data屬性中.

          <script>
              export default {
                  name: "calculate",
                data() {
                    return {
                      counter: 0
                    };
                }
              }
          </script>
          

          然后,在頁面中通過語法糖直接引用counter變量. counter的值就在頁面中顯示了.
          最后, 我們還可以在頁面中增加action, 比如點擊事件, 來改變state的狀態.

          以上是在單頁面中狀態管理的流程.

          2.2. 多界面狀態管理

          舉個例子, 比如,我們有一個calculate.vue組件

          
                data() {
                    return {
                      counter: 0
                    };
                },
                methods: {
                    add() {
                      this.counter ++
                    },
                    dev() {
                      this.counter --
                    }
                }
              }
          </script>
          

          然后在App.vue中引入calculate.vue組件

          <script>
          import Calculate from './views/calculate'
          
          export default {
            name: 'App',
            components: {
              Calculate,
            }
          }
          </script>
          

          這時, 如果想要在App.vue中使用calculate.vue中定義的變量counter, 可以么?
          直接使用肯定會報錯, 但Calculate和App兩個組件的關系是父子組件, 可以使用父子組件變量傳遞的方式實現.

          如果不是父子關系呢? 需要如何實現呢?我們可以使用vuex.

          2.3. Vuex的使用

          使用vuex, 首先需要安裝vuex組件

          npm install vuex --save
          --save表示的含義是: 運行時需要

          組件安裝好了, 下面就來看看怎么用吧.

          第一步: 添加vuex代碼文件夾

          在src目錄下新建/src/store/index.js. 通常, vuex都放在store文件夾里面. 然后在store下面創建一個文件index.js

          第二步: 在index.js文件中定義vuex組件.

          vuex是一個插件, vue-router也是一個插件, 插件的使用方式都是類似的.

          1: 引入vue和vuex

          import Vue from 'vue';
          import Vuex from 'vuex';
          

          2: 安裝vuex

           Vue.use(Vuex);
          

          3: 創建vuex對象

          const store = new Vuex.Store({
              state: {
              },
              mutations: {
              },
              actions: {
              },
              getters: {
              },
              modules: {
              }
          })
          

          在store中定義了5個對象, 這5個對象是固定的. 每個對象的含義是什么呢? 后面在詳細說.

          4: 導出vuex

          export default store;
          

          5: 在main.js中引入vuex

          import Vue from 'vue'
          import App from './App'
          import router from './router'
          import store from './store/index';
          
          Vue.config.productionTip = false
          
          /* eslint-disable no-new */
          new Vue({
            el: '#app',
            store,
            router,
            render: h => h(App)
          })
          

          接下來在來看看2.2中多界面狀態管理的問題. calculate組件中有一個counter, 在父組件App.vue中想要使用counter, 這時候, 這個counter就是一個公共的狀態了, 可以將其定義在vuex中.

          2.4 Vuex實現多界面狀態管理

          下面來看看使用vuex的方式如何實現呢?

          1. 在vuex的state中定義一個變量counter

          // 第三步: 創建vuex對象
          const store = new Vuex.Store({
            state: {
              counter:0
            }
          })
          

          2. 在calculate.vue中使用$store.state.counter來獲取vuex中counter變量

          <template>
            <div>
              <h2>{{$store.state.counter}}</h2>
            </div>
          </template>
          

          這樣就顯示出來了counter變量了. 并且, 可以在calculate.vue或者App.vue, 或者任何其他組件中都可以直接使用. 如下圖所示:

          接下來要實現+和-的操作.
          這個怎么實現呢? 我們可能會這么想

          <template>
            <div>
              <h2>-------calculate.vue-------</h2>
              <h2>{{$store.state.counter}}</h2>
              <button v-on:click="$store.state.counter++">+</button>
              <button v-on:click="$store.state.counter--">-</button>
            </div>
          </template>
          

          $store.state.counter++或者$store.state.counter--不就可以了么?
          雖然, 這樣也能達到效果, 但是Vuex官網推薦我們不要這樣使用, 原因是, 這樣操作完, 我們不能跟蹤到狀態的變化. 這是什么意思呢, 這就要來看看vuex的設計思想了.

          2.5 Vuex式的設計思想

          Vuex實質是單例模式的設計思想

          • 將共享的狀態抽取出來, 交給大管家, 進行統一管理
          • 之后, 每一個視圖, 按照規定好的規則, 執行訪問或修改等操作.
          • 這就是vuex背后的思想.

          這里規定好的規則很重要. 規定好的規則是什么規則呢? 我們來看一下vuex官方給出的一個圖

          這里面一共有5個元素

          • Vue compontents
          • State
          • Mutations
          • Action
          • Devtools

            這幾個部分都是做什么用的呢?

          1. Vue Components

          在這個圖里面綠色的部分是Vue compontents(Vue組件), Vue組件可以引用state變量, 還可以觸發操作修改變量的值.

          2. State:

          State用來存儲的是變量, 變量值可以直接渲染到Vue組件上, 但是約定好的, Vue組件不可直接修改State的值

          3. Mutations 和 Devtools

          如果Vue組件想要修改state中的狀態, 他不能直接修改State, 而是需要執行commit, 提交到Mutations, 由Mutations觸發修改state的狀態. 為什么要這樣呢? 這就和Devtools有關系了.

          我們看到有一塊灰色的Devtools, 這是什么呢? 這是Vue開發的一款瀏覽器插件. 這個插件可以幫助我們記錄每次state中變量修改的狀態, 為什么要記錄state的狀態呢?

          比如, 我們有多個組件同時修改vuex中的一個狀態, 那么大家都來改, 最終這個值是誰改的呢? 如果沒有記錄狀態變化, 那么我們就不知道是誰改的了. Vue提供的Devtools工具, 就可以用來記錄每次修改的狀態.

          但是, 如果我們直接修改組件, 那就沒有經過Devtools的流程, Devtools也就記錄不了了. 也就是直接從state修改變量值(紅色箭頭), 而不是走藍色箭頭的流程, 那么沒有經過Devtools, Devtools也不能記錄上修改的狀態了.

          4. Action

          Action主要是用來進行異步處理操作的. mutations是用來處理同步操作的, 所以, vue組件想要修改變量的時候, 直接走mutations就可以了, 這樣也可以通過Devtools來記錄修改情況. 但是, 如果異步怎么辦呢? devtools只能用來記錄同步狀態, 如果出現異步, 他就記錄不了了. 所以, 這里多了一個action. action就是用來處理異步操作的. 當action處理完了以后, 再交給Mutations來處理, 這時候就是同步的操作了, Devtools也可以處理了.

          什么情況會進行異步操作呢?
          發送網絡請求. 所以在Action模塊指向了BackEnd, 向后端發送網絡請求.

          2.6 Devtools的使用

          1. 安裝Devtools

          下面我們就來安裝Devtools
          打開google瀏覽器, 點擊右上角三個點-->更多工具-->擴展程序-->打開Chrome網上應用店-->搜索Devtools, 如下圖:

          找到VueJs的Devtools-->添加至Chrome, 如下圖:

          然后安裝插件即可.

          2. 使用Devtools跟蹤狀態

          Chrome安裝好Devtools以后,打開控制臺, 在菜單欄最后多了一個vue, 點開可以看到如下界面:

          其中,第二個按鈕是監控變量狀態變化的.

          我們如果直接使用$store.state.counter++, 在Devtools是無法監控狀態變化的,但是如果我們使用mutations就可以監控到狀態變化.

          3.在mutation中修改counter的值

          首先, 我們是要在頁面實現+和-的邏輯, 如下圖:

          這個邏輯在calculate.vue組件會用到, 在App.vue組件也會用到, 因此我們將其定義在vuex插件中. 在插件里面定義兩個方法:increase()和decrease(), 修改變量counter的值

          const store = new Vuex.Store({
            state: {
              counter: 100
            },
            mutations: {
              increase(state) {
                state.counter ++;
              },
              decrease(state) {
                state.counter --;
              }
            }
          })
          
          

          這兩個方法increase()和decrease(), 他們自帶的參數就是state.

          在調用方如何定義呢? 也就是calculate.vue和App.vue中應該如何使用Vuex中定義的兩個mutations方法呢?

          <template>
            <div>
              <h2>-------calculate.vue-------</h2>
              <h2>{{$store.state.counter}}</h2>
              <button v-on:click="add()">+</button>
              <button v-on:click="sub()">-</button>
            </div>
          </template>
          
          <script>
              export default {
                  name: "calculate",
                data() {
                    return {
          
                    };
                },
                methods: {
                  add() {
                    this.$store.commit("increase");
                  },
                  sub() {
                    this.$store.commit("decrease")
                  }
                }
              }
          </script>
          

          在調用方, 我們要使用this.$store.commit()的方式來提交變更.

          在左側點擊+或-,在右側devtools都會記錄每一次狀態變化.

          2.7 總結

          Vuex 應用的核心就是 store(倉庫), “store”基本上就是一個容器,它包含著你的應用中大部分的狀態 (state)。Vuex 和單純的全局對象有以下兩點不同:

          1. Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那么相應的組件也會相應地得到高效更新。
          2. 你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地了解我們的應用。

          四. Vuex的核心概念

          Vuex的核心概念一共有5個

          • State
          • Getter
          • Mutations
          • Action
          • Modules

          這幾個概念: 其中State, Mutations, Action上面都有提高過. 下面重點來看看Getter和Modules. 在看Getter之前先來看一個概念: 單一狀態樹

          4.1 單一狀態樹

          什么是單一狀態樹呢?

          比如我們的個人信息,社保信息存在社保系統里, 公積金信息存在公積金系統里, 醫保信息存在醫保系統里. 這有有好處也有壞處, 好處是信息更安全,彼此隔離; 壞處是要是辦某一件事,想要所有的信息, 就要跑很多地方取.

          而單一狀態樹的含義就是將所有的信息都存在一個store中, 如果需要什么數據, 直接去那一個store中取就好了. 不要在系統中定義多個store, 這樣不方便管理和維護.

          單一狀態樹的含義: 在一個項目只建一個store.

          4.2 Getter的使用

          Getter有些類似于compute計算屬性. 什么時候使用計算屬性呢? 當我們需要將一個屬性的值經過計算以后顯示出來, 這時候我們通常使用計算屬性.

          Getter也是如此: 當一個state屬性需要計算以后顯示出來, 我們就可以使用Getter屬性.
          比如現在要計算counter的平方.

          如果不使用計算屬性,我們怎么做呢? 在calculate.vue組件里我們是這么寫的.

          <h2>{{$store.state.counter * $store.state.counter}}</h2>
          

          1. 使用計算屬性計算平方

          然后, 如果在App.vue中也要這么用, 就再來一段. 觀察: 這代碼很長, 不利于維護, 我們可以將其放到Getter中. 統一計算以后返回

          const store = new Vuex.Store({
            state: {
              counter: 100
            },
            mutations: {
              increase(state) {
                state.counter ++;
              },
              decrease(state) {
                state.counter --;
              }
            },
            getters: {
              // getter中第一個參數是state
              powerCounter(state) {
                return state.counter * state.counter
              }
            }
          })
          

          這里定義了一個計算平方的方法powerCounter(), 他的第一個參數是state, 所以, 我們可以直接拿到counter屬性進行操作. 接下來在調用方如何調用呢?

           <h2>{{$store.getters.powerCounter}}</h2>
          

          通過$store.getters.powerCounter獲取計算屬性.

          2. 在getters中定義方法的第二個參數

          如果我們在另一個方法里想要使用其他getters計算方法怎么辦呢? 在getters中定義的方法還有默認的第二個參數getters
          例: 計算counter的平方 + 100
          這時候我們可以怎么做呢? 如下定義了powerAndAdd方法, 其第二個參數默認是getters.

          getters: {
              // getter中第一個參數是state
              powerCounter(state) {
                return state.counter * state.counter
              },
          
              powerAndAdd(state, getters) {
                return getters.powerCounter + 100
              }
            }
          

          我們在powerCounter已經做了平方的操作了, 接下來我們可以直接使用這個的結果來計算.
          在powerAndAdd方法中, 第一個參數依然是state, 第二個參數是getters. 我們可以通過getters獲取到第一個方法powerCounter, 然后在第一個方法的基礎上+100.

          在calculate.vue組件中調用powerAndAdd方法

          <template>
            <div>
              <h2>-------calculate.vue-------</h2>
              <h2>{{$store.state.counter}}</h2>
              <button v-on:click="add()">+</button>
              <button v-on:click="sub()">-</button>
              <h2>counter取平方: {{$store.getters.powerCounter}}</h2>
              <h2>平方后+100: {{$store.getters.powerAndAdd}}</h2>
            </div>
          </template>
          

          最終效果如下:

          3. 在getters中自定義帶參數的方法

          在getter中, 前面說了, getters中定義的方法, 第一個參數是state, 第二個參數是getters. 這兩個都是默認的. 如果我有一個方法想要傳自定義參數怎么辦呢?
          不能直接在getters后面添加, 可以使用匿名函數接收自定義參數. 比如下面的add方法

          getters: {
             // getter中第一個參數是state
             powerCounter(state) {
               return state.counter * state.counter
             },
          
             powerAndAdd(state, getters) {
               return getters.powerCounter + 100
             },
          
             add(state, getters) {
               return (num1, num2) => num1 + 100 + num2;
             }
           }
          

          在使用的時候, 直接傳遞兩個參數就可以了,方法如下:

          <h2>累加+100: {{$store.getters.add(200, 500)}}</h2>
          

          4.3 Mutations的使用

          1. Vuex中store狀態修改的唯一方式:提交Mutations

          1. Mutations 主要包含兩部分
          • 一部分是事件類型(type)
          • 另一部分是回調函數(handler), 回調函數的第一個參數是state

          例如:

          mutations: {
              increase(state) {
                state.counter ++;
              },
              decrease(state) {
                state.counter --;
              }
            }
          

          我們可以理解為increase是事件類型type, 方法體是回調函數. 回調函數的第一個參數是state

          mutations方法定義好以后, 如果我們想要調用, 使用commit提交的方式調用

          add() {
            this.$store.commit("increase");
          },
          

          2.Mutations傳遞參數

          在之前計算頁面有一個+和-, 如果需要+5, +10, -100這時候怎么處理呢? 我們需要定義一個方法, 接收參數 在Mutation中如何定義參數, 又如何傳遞參數呢?

          在Mutation中有兩種數據提交的方式

          1. 第一種數據傳遞的方式

          我們來看看步驟:
          第一步: 在calculate.vue組件定義兩個按鈕, 一個+5, 一個加 +10

              <button v-on:click="addCount(5)">+5</button>
              <button v-on:click="addCount(10)">+10</button>
          

          在定義一個方法addCount()

               methods: {
                      add() {
                        this.$store.commit("increase");
                      },
                      sub() {
                        this.$store.commit("decrease")
                      },
                      addCount(num) {
          
                      }
              }
          

          第二步: 在store中定義一個mutation方法, 并且接收一個參數, 如下increaseCount

          mutations: {
              increase(state) {
                state.counter ++;
              },
              decrease(state) {
                state.counter --;
              },
              increaseCount(state, num) {
                state.counter += num;
              }
          }
          

          increaseCount()方法第一個參數是state, 我們可以用第二個參數來接收變量. 這和getter是不一樣的, getter需要寫一個匿名函數來接收自定義變量
          第三步: 在定義好的calculate組件中調用store的increaseCount方法

                  addCount(num) {
                    this.$store.commit("increaseCount", num)
                  }
          

          在傳遞參數的時候, 我們將自定義參數放在第二個變量位置.

          第四步: 查看效果

          1. 第二種數據傳遞的方式

          第一種數據傳遞的方式是具體的參數, 第二種數據傳遞的方式傳遞的是對象. 我們來看看第二種

          下面來對比比較:
          之前使用的是直接傳遞參數的方式

                  addCount(num) {
                    this.$store.commit("increaseCount", num)
                  },
          

          使用對象傳遞參數怎么寫呢?

          addCount(num) {
                    this.$store.commit({
                      type: "increaseCount",
                      num: num
                    })
                  },
          

          需要注意的是, 寫法不同, 含義有略有區別.

          • 方式一傳遞到mutation中的是具體的參數值.
          • 方式二傳遞到mutation中的是一個對象.

          同樣是在mutation中定義方法, 并接受一個參數obj

           increaseCount(state, obj) {
                console.log(obj);
            },
          

          第一種方式傳遞過來的是:


          可以看到傳遞過來是具體參數的內容

          第二種方式傳遞過來的是一個對象

          觀察右側控制臺, 傳輸傳遞過來的是一個對象, 并且是所有參數的對象. 所以, 如果增加num數字, 需要獲取obj.num

              increaseCount(state, obj) {
                console.log(obj);
                state.counter += obj.num;
              },
          

          3. Mutation的響應規則

          Vuex的store的state是響應式的, 當state中的數據發生改變時, Vue組件會自動更新.
          但是, 需要準守對應的規則

          1) 增加新屬性

          比如: 我們修改info的name參數.先來看效果

          第一步: 在store/index.js的state中定義變量info, 并定義修改info的方法updateInfo

          const store = new Vuex.Store({
            state: {
              info: {
                name: "王五",
                age: 58,
                sex: "男"
              }
            },
            mutations: {
              updateInfo(state, name) {
                // 修改info中name的值
                state.info["name"] = name;
              }
            }
          })
          

          第二步: 在calculate.vue中展示info內容, 并修改info的內容

          <template>
            <div>
              <h2>-------calculate.vue-------</h2>
              <h2>info: {{$store.state.info}}</h2>
              <button v-on:click="updateInfo">修改name</button>
            </div>
          </template>
          
          <script>
              export default {
                name: "calculate",
                methods: {
                  updateInfo() {
                    this.$store.commit("updateInfo", "趙六")
                  }
                }
              }
          </script>
          

          這里直接調用的是store中的mutation方法updateInfo(). 在updateInfo()方法中, 使用state.info["name"]=name的方式重置了name的值,并且在頁面立刻響應式的看到了效果

          但是, 不是在任何情況使用state.info["name"]=name賦值都是響應式的, 我們來給info增加一個hobby試一試
          第一步: 在store/index.js中增加mutation方法, 添加愛好hobby, hobby屬性之前在info中是沒有的

              updateInfoHobby(state, hobby) {
                state.info["hobby"] = hobby
                console.log(state.info)
              }
          

          第二步: 定義方法修改hobby

                  updateInfoHobby() {
                    this.$store.commit("updateInfoHobby", "籃球")
                  }
          

          第三步: 看效果

          我們發現, 點擊按鈕添加hobby以后, 頁面并沒有響應式的添加hobby, 但是在右側控制臺看到$store.info中確實已經有hobby屬性.

          這就是我們要說的Mutation修改state屬性的第一個條件:
          要想實現響應式展示, 需要提前在store中初始化好屬性. 如果有些屬性是動態添加的, 提前不知道怎么辦呢? 我們需要換一種方式添加

          updateInfoHobby(state, hobby) {
                Vue.set(state.info, "hobby", hobby);
              }
          

          來看看效果:

          還有一種方式: 就是使用完整的新對象給就對象賦值.

          總結:

          提前在store中初始化好需要的屬性當給state中的對象添加新屬性的時候,使用下面的方式
          方式一:使用Vue.set(obj, newProp, value)

          方式二: 用新對象給就對象賦值

          2) 刪除屬性

          當我們需要刪除屬性的時候, 也是使用Vue.delete(obj, prop)可以做到響應式展示

          4. Mutation的類型常量

          在mutation中, 我們定義了很多事件類型(也就是方法名), 當我們的項目變大時, vuex管理 狀態越來越多, 需要更新狀態的情況越來越多, 那么意味著Mutation中的方法越來越多. 方法多了,名稱就容易出錯, 所以我們將Mutation中的常量提取出來. 放在一個公共文件中定義,下面來看看如何實現:
          以修改counter方法為例. 我們來將自增方法increase提取出來.

          第一步: 新增一個mutation-types.js 文件, 定義一個常量INCREASW

          export const INCREASW = "increase"
          

          第二步. 在store的mutation中使用常量定義方法名

          // 引入mutation
          import { INCREASW} from './mutation-types'
          
          const store = new Vuex.Store({
           mutations: {
              [INCREASW](state) {
                state.counter ++;
              }
           }
          })
          

          這里使用[]來定義方法名, 作為變量傳入.

          第三步: 在calculate.vue中引入mutation-types并且使用commit提交到mutation

           import {INCREASW} from '../store/mutation-types'
                  add() {
                    this.$store.commit(INCREASW);
                  },
          

          這樣就提取了變量. 當需要修改變量名的時候, 我們不用每個地方都修改, 只需要修改mutation-types中的變量名的值.

          5 Mutation同步函數

          通常情況下, Vuex要求我們Mutation中的方法必須是同步方法. 為什么呢?
          主要的原因是, 當我們使用devtools工具時, devtools工具可以很好的幫我們捕捉mutation的快照. 但如果是異步操作, 那么devtools將不能很好地追蹤到這個操作是什么時候完成的.

          舉個例子:
          我們將[修改name]這個動作進行異步處理. 放在setTimeout中,

             updateInfo(state, name) {
                setTimeout(function(){
                  state.info["name"] = name;
                }, 1000)
              }
          

          然后點擊[修改name]按鈕, 會發現將王五的名字改為趙六, 頁面改了, 但是在devtools工具中沒有改, 如下圖:

          這個問題就是上面說的, 在Mutation中盡量不要執行異步操作, 要是執行異步操作, devtools可能跟蹤不上.
          如果確實有異步操作, 那么就使用action. action的功能類似于Mutation, 但是它主要是處理異步操作的. 下面就來看看Action的使用

          4.4 Action的使用

          上面已經說過了, action的用法和Mutation的用法類似. 但action主要是處理異步操作. 如何將寫在mutation中的updateInfo方法中異步操作替換到action中實現呢?

          在mutation中定義的方法

              updateInfo(state, name) {
                setTimeout(function() {
                  state.info["name"] = name;
                }, 1000)
              }
          

          在action中定義的方法

          actions:{
              aUpdateInfo(context) {
                setTimeout(function () {
                  context.commit("updateInfo")
                }, 1000)
              }
            },
          mutations: {
              updateInfo(state, name) {
                state.info["name"] = name;
              }
          }
          

          我們定義了一個和updateInfo對應的方法 aUpdate. 入參是context, 注意這里不是state了, 而是整個store. 異步操作定義在aUpdate方法中, 然后調用Mutation中的方法.
          注意: 這是官方要求的, action不要自己去修改state, 所以修改state的操作都在Mutation中進行.

          接下來, 在按鈕[修改name]的時候, 重新定義click事件, 這次就不能直接指向mutation了, 而是要指向action.
          * 調用mutation的方法使用: this.$store.commit(...)
          * 調用action的方法使用: this.$store.dispatch(...)

              updateInfo() {
                // 調用mutation
                // this.$store.commit("updateInfo", "趙六")
                // 調用action
                this.$store.dispatch("aUpdateInfo", "趙六")
              },
          

          效果如下圖所示:

          可以看到這會devtools識別了info信息的變化

          4.5 Module的使用

          Module的含義是模塊, 我們為什么要在Vue中引入模塊呢?

          1. Vue使用的是單一狀態樹, 那么也就是說很多狀態會交給vuex來管理
          2. 當應用變得復雜是, store也會變得很臃腫,
            為了解決這個問題, Vuex允許我們將store分割成模塊. 每個模塊都擁有自己的states, mutations, actions, getters 等等

          寫法如下:

          const store = new Vuex.Store({
            modules:{
              a:{
                state: {
          
                },
                getters:{
          
                },
                mutations:{
          
                },
                actions: {
          
                }
              },
              b: {
          
              }
            }
          })
          

          如上, 在store中定義了一個modules, 里面有兩個模塊a和b, a模塊中定義了一套getters, states, mutations, actions, b模塊也可如此定義

          那么定義好以后如何使用呢? 下面一個一個來看

          1. state調用

          在store/index.js文件中定義一個moudules, 然后定義state

          const module1 = {
            state: {
              message: "這是定義在module1中的state"
            },
          }
          
          const store = new Vuex.Store({
            modules:{
              module1: module1
            }
          }
          

          如上展示, 如何調用module1中的message呢?

              <h2> message : {{$store.state.module1.message}} </h2>
          

          2. getter 調用

          在module1中增加getters

          const module1 = {
            state: {
              message: "這是定義在module2中的state"
            },
            getters:{
              extraMessage: function(state){
                return state.message + "aaaa";
              }
            }
          }
          

          前面介紹過getters中定義的屬性, 就相當于computed計算屬性.
          接下來看看如何調用getters中的計算屬性呢?

          <h2> extraMessage: {{$store.getters.extraMessage}}</h2>
          

          在調用的時候, 和state有些不同. 這里不需要指定modules模塊名. 首先回去store中定義的getters查找, 抄不到再去modules1模塊中查找,所以, 我們在定義的時候,盡量不要重名

          3. mutation的調用

          我們定義一個按鈕來更新 message的值

          const module1 = {
            state: {
              message: "這是定義在module2中的state"
            },
            getters:{
              extraMessage: function(state){
                return state.message + "aaaa";
              }
            },
            mutations:{
              changeMessage: function(state) {
                state.message = "替換成新的message"
              }
            },
            actions: {
          
            }
          }
          

          接下來看調用方, 定義一個按鈕, 替換message的值. 然后changeMessage

          <button v-on:click="changeMessage">替換message</button>
          
                  changeMessage() {
                    this.$store.commit("changeMessage")
                  }
          

          我們看到在調用mutation中的方法的時候, 直接使用的是 commit. 和調用store中mutation是一樣的.
          這里還可以傳遞參數, 方式方法也和在store中一樣

          4. action的調用

          我們在修改message信息的地方將其設置為異步修改, 寫法如下:

          const module1 = {
            state: {
              message: "這是定義在module2中的state"
            },
            getters:{
              extraMessage: function(state){
                return state.message + "aaaa";
              }
            },
            mutations:{
              changeMessage: function(state) {
                state.message = "替換成新的message" + ", bbbb";
              }
            },
            actions: {
              aChangeMessage: function(context) {
                setTimeout(() => {
                  context.commit("changeMessage")
                }, 1000)
              }
            }
          }
          

          在actions中增加了一個setTimeout, 這就是異步的. 調用方在調用的時候, 需要使用dispatch指向actions的方法

                  changeMessage() {
                    this.$store.dispatch("aChangeMessage")
                  }
          

          以上就是在modules中定義states, getters, mutations, actions的方法的使用

          至此Vuex的用法就全部完事了.


          主站蜘蛛池模板: 无码人妻一区二区三区在线水卜樱| 亚洲一区精品中文字幕| 一区在线免费观看| 视频在线观看一区二区三区| 色噜噜AV亚洲色一区二区| 91久久精品午夜一区二区| 一区二区三区免费在线观看| 99偷拍视频精品一区二区| 无码一区二区三区免费| 日本高清成本人视频一区| 香蕉久久AⅤ一区二区三区| 精品一区精品二区制服| 无码人妻精品一区二区三区在线| 精品一区二区三区色花堂| 精品视频一区二区三区在线播放| 亚洲色精品VR一区区三区 | 午夜一区二区免费视频| 亚洲一区二区三区播放在线| 中文字幕日韩人妻不卡一区| 亚洲视频在线一区二区| 一区二区三区精品视频| 午夜精品一区二区三区在线视| 日韩免费无码一区二区视频| 波多野结衣AV一区二区三区中文 | 亚欧在线精品免费观看一区| 免费播放一区二区三区| 色偷偷一区二区无码视频| 无码人妻精品一区二区三| 日韩人妻无码一区二区三区久久| 国产精品区一区二区三在线播放| 日本成人一区二区| 少妇无码一区二区三区免费| 91福利一区二区| 亚洲一区二区三区在线观看网站| 亚洲欧美国产国产综合一区 | 国产高清不卡一区二区| 一区二区三区四区精品视频| 亚洲一区二区三区不卡在线播放| 韩国美女vip福利一区| 亚洲日韩国产一区二区三区在线| 亚洲AV成人精品一区二区三区|