日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

Vue阶段总结

發布時間:2023/12/18 vue 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vue阶段总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Vue總結

vue的簡介

Vue的特點和Web開發中常見的高級功能:

? 1、解耦視圖和數據

? 2、雙向數據綁定

? 3、可復用的組件

? 4、前端路由技術

? 5、狀態管理

? 6、虛擬DOM(js對象)

學習vue的注意點

注意:

? 學習Vue框架,必須嚴格遵循他的語法規則,Vue代碼的書寫思路和以前的JQuery完全不一樣。所以,在項目中使用Vue之前,必須先學習Vue的基本語法規則。

Vue 安裝使用

方式一:直接CDN引入

<!-- 開發環境版本,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 生產環境版本,優化了尺寸和速度 --> <script src="https://cdn.jsdelivr.net/npm/vue"></script>

方式二:下載和引入

// 開發環境 https://vuejs.org/js/vue.js // 生產環境 https://vuejs.org/js/vue.min.js

方式三:NPM安裝(今天先不掌握)

? 后續通過Vue-Cli4(腳手架)方式引入,我們使用該方式

創建Vue對象

  • 先看js代碼,會發現創建了一個Vue對象

  • 創建Vue對象的時候,傳入了一個對象:{}

    2.1 {}中的el屬性:該屬性決定了這個Vue對象掛載到哪一個元素上,很明顯,我們這里掛載到了id為app的元素上。

    2.2 {}中包含了data屬性:該屬性中通常會存儲一些數據,好像上面例子中的str1就是直接定義出來的數據

  • <script>var vm = new Vue({ //這個Vue對象用來控制某一個標簽里面的數據el:"#app", //要控制的標簽data:{str1:"hello vue", //定義一個數據,在id為app的標簽內部去使用}}) </script>可以在里面填入正則表達式,變量,可以進行加減乘除等的運算或者字符串拼接

    定義Vue對象基本格式

    var vm = new Vue({el: "要綁定的標簽",data: {變量名1:值1,變量名2:值2,變量名3:值3,...},methods: {方法名1: function(){},方法名2: function(){},方法名3: function(){}}});

    Vue常見的語法格式(重點)

    插值

    {{ 變量key值 }}

    v-bind控制標簽屬性

    <a v-bind:href="bd">百度</a><a :href="tb">淘寶</a>可以使用簡寫 ‘:’

    v-on事件格式

    <button v-on:click="num+=1">點我數字增加</button><button v-on:click="add">點我數字加5</button><button @click="add2(10)">點我數字加10</button>簡寫方法 “@”如果使用函數,必須在創建的Vue對象里面,添加methodsmethods:{add:function(){this.num += 5},add2(){this.num += 10}

    vue控制類名

    <div id="app"><!--控制標簽的類名 :class= 的值可以是 js對象 {類名:布爾值} --><div class="box" :class="{box1:bool1, box2:bool2}"></div><!--控制標簽的類名 :class= 的值可以是 數組 [類名1,類名2] -->可以是多個的類名<div class="box" :class="['box3', 'box4']"></div><!--掌握--><div class="box" :class=" bool3 ? 'current':'' "></div><!--通過控制bool3位真還是假,來控制這個盒子有還是沒有current這個類-->

    style樣式(動態控制類名)

    <div :style="{fontSize:'40px' }">文字</div>可以使用對象<div :style="{ fontSize:false?'40px' : '50px'}">文字</div>可以使用數組<div :style="[{fontSize:false?'40px' : '50px'},{background:'pink'}]">文字</div></div> <!-- 第一種綁定class --> <div :class="['classA', 'classB']"></div><!-- 第二種綁定class --> <div :class="{'classA': true, 'classB' : false}"></div><!-- 第一種綁定style --> <div :style="{fontSize: '16px', color: 'red'}"></div> :style="{'background-image': 'url('+userInfoFn.headImg變量+')'}"<!-- 第二種綁定style --> <div :style="[{fontSize: '16px', color: 'red'}]"></div>三元表達式: :class="['iconfont樣式名',item.checked變量()? 'true走這邊': 'false走這邊']"

    控制標簽是否顯示

    v-show

    v-show是對樣式層面的控制

    例如

    <p v-show = 'turn'>新聞</p> 在頁面中的顯示是 <p style="display: none;">新聞</p>style="display: none

    v-if

    v-if是對dom節點的控制

    例如: v-if指令的作用: 控制標簽是否展示,不展示則刪除

    常與 v-eles 一起用(中間可以插入別的,但是一般識別距離最近的 v-if ; v-eles)<!--<div v-if="bool1">11111</div>--> <!--<div v-else>222222</div>-->bool1的值為true 第一個盒子被保留,刪除第二個盒子,為false的話,第2個盒子保留,刪除第1個盒子

    兩者的具體應用

    v-show 一般用于頻繁切換操作,否則可以使用v-if

    列表的渲染(v-for)

    語法:v-for="(item, index) in 需要遍歷的數組數組"元素 索引具體用法: <li v-for="i in list1">{{ i }}</li>還可以做數組的添加和刪除 unshift > 在前面新增 push > 在后面新增 shift > 在前面刪除 pop > 在后面刪除

    對象的渲染(v-for)

    語法:v-for="(value, key) in 需要遍歷的對象"value值 key值具體的用法:<!--i是my_obj對象中的值 j是my_obj對象中的鍵名--><li v-for="(i, j) in my_obj">{{i}} {{j}}</li>

    表單數據綁定(雙向數據綁定)

    v-model的值是,vue接收表單元素的值的變量名, 即v1的值就是用戶填寫的內容
    (甚至可以在data中設置v1的值,從而設置表單元素的默認值)

    可以設置初始值,捕獲改變后的值(最新的值)

    可以做tab欄的切換

    <div id="app"><input type="text" v-model="txt1"> <!-- v-model表示了用戶輸入的這個數據--><p>{{ txt1 }}</p><select v-model="sel1"><option value="0">北京</option><option value="1">上海</option><option value="2">廣州</option></select></div><script>var vm = new Vue({el:"#app",data:{//通過改變txt1或者sel1,來使對應的表單元素的v-model的值發生了變化,所以這個表單元素的value就變化了(v-model看成我們之前將的value)txt1: '默認值',sel1: 0}})</script>

    模板語法的插值操作(其他不常用指令)

    v-html 往標簽內部插入html文本

    data:{htmlText:"<p>你好!世界!</p>"}<p v-html = "htmlText"></p> 顯示:你好!世界!

    v-text 往標簽內部插入普通文本(解析不了標簽)

    <p v-text = "htmlText"></p> 顯示:<p>你好!世界!</p>

    v-pre 在界面上直接展示胡子語法

    <p v-pre>{{htmlText}}</p> 顯示:{{htmlText}}

    v-cloak 隱藏數據渲染到頁面之前,胡子語法在界面上的展示

    <p v-cloak>{{htmlText}}</p>搭配 style 隱藏 使用<style>[v-cloak]{display: none;}</style>如果不使用隱藏,在加載完成之前,顯示:{{htmlText}} 加載完成之后,顯示:<p>你好!世界!</p>與加載的網絡有關

    數組方法

    常用方法使用

    var arr = [1, 2, 3] // 往數組最后一位添加一個數字 arr.push(4) // [1, 2, 3, 4] // 刪除數組最后一個數字 arr.pop() // [1, 2, 3] console.log(arr) // 往數組第一位添加一個數字 arr.unshift(0) console.log(arr) // 刪除數組第一個元素 arr.shift() console.log(arr) // splice // 刪除第一個元素 arr.splice(1, 2) console.log(arr) arr.splice(1, 2, 2, 4, 5) console.log(arr) // 合并數組 console.log([1, 6].concat([5, 7]))

    push(返回數組長度)、unshift(返回數組長度)、shift(返回刪除的值)、pop(返回刪除的值)、splice、concat(返回新數組)

    filter方法

    過濾

    let arr = [1, 2, 3, 4, 5, 6]// filter() 過濾 ,如果是true 則保留,如果是false 則過濾// 不會修改原數組let new1 = arr.filter((item, index) => {return item > 3})console.log(new1, arr);//?[4, 5, 6] [1, 2, 3, 4, 5, 6]

    map方法

    // map() 修改數組里面的每一個元素,并且新的數組和舊的數組長度是一樣的// 不會改變原數組let new2 = arr.map((item, index) => {return item + 2})console.log(new2);//[3, 4, 5, 6, 7, 8]let new3 = arr.map((item, index) => {return {id:item+2}})console.log(new3);//?[{…}, {…}, {…}, {…}, {…}, {…}]

    reduce方法

    利用reduce方法遍歷數組的每一個元素,reduce()調用結果最后返回一個最終值(最后一次return值)。

    //數組名.reduce(回調函數,pre的初始值)arr.reduce(function(pre, current){// reduce這個方法被調用時,會遍歷arr這個數組的每一個元素,每遍歷一個元素,就執行一次這里的代碼// current表示當前正在遍歷的這個元素// pre 是上一次的這個函數return的值// !!!因為第一次遍歷沒有上一個return值,所以,交給了第二個參數,設置pre的初始值console.log(pre, current)return 10},0)//!!!并且reduce方法最終會返回最后一次的return值每一次,都返回pre// reduce: 遍歷數組,不會改變原數組/*特點:1、reduce 第二個參數如果沒有,name第一次的prev取數組的第一個元素,回調函數是從數組的第二個元素開始如果有第二個參數,name第一次的prev的值用的就是傳入reduce的第二個參數,回調函數從數組的第一個元素開始遍歷2、reduce里面的prev的值,第一次是由reduce第二個參數決定的,其他的情況下是上一次回調函數的返回值所決定的。reduce 返回值就是最后一次回調函數的返回值。*/用處:可以做計算,匯總…… 語法: array.reduce(function(total, currentValue, currentIndex, arr), initialValue)(total 必填;初始值或者計算結束后的返回值(后面沒有初始值,默認初始值為數組的第一個數 prev的第一次等于數組的第一個數) (currentValue 必填 當前元素) (currentIndex 可填 當前元素的索引) (arr 可選 當前元素所屬的數組對象)(initialValue 可選。傳遞給函數的初始值 不填,默認是數組的第一個數,然后從第二數開始遍歷)其余prev 都是undefined 因為沒有返回 return

    數組去重

    var arr2 = [1, 2, 3, 1, 6, 2, 3]//ES6consoloe.log([...new Set(arr2)])console.log(Array.from(new Set(arr2)))var newArray = [];for(var i=0; i<arr2.length; i++){if(newArray.indexOf(arr2[i])==-1){newArray.push(arr2[i])}}console.log(newArray)var newArray2 = [];var obj = {};for(var i=0; i<arr2.length; i++){if(!obj[arr2[i]]){ //如果不在obj中,就表示不重復的數據,就在對象中添加鍵值對obj[arr2[i]] = arr2[i]newArray2.push(arr2[i])}}console.log(newArray2)

    Vue的計算屬性computed 的使用

    computed:{//computed里面的方法必須有返回值!這個return值將來在視圖中被{{total}}引用***函數 無法傳入參數total(){var a = this.arr.reduce(function(pre, current){console.log(pre, current)// var total = 當前這次的 price*count + 上一次的totalvar total = current.price*current.count + prereturn total},0)return a}}

    computed內部方法有緩存的作用

    函數調用了三遍,卻只執行了1遍,這是computed內部方法的緩存起了作用

    computed內部方法的另一種寫法(知道有get和 set的格式)

    ....computed:{//computed里面的方法必須有返回值!這個return值將來在視圖中被{{total}}引用total:{get(){console.log("total_get")var a = this.arr.reduce(function(pre, current){// var total = 當前這次的 price*count + 上一次的totalvar total = current.price*current.count + prereturn total},0)return a},set(){console.log("total_set")},}}...vm.total = 3 //觸發調用set方法

    使用:value和@input代替v-model

    v-model 本質上包含了兩個操作:

  • v-bind 綁定input元素的value屬性
  • v-on 指令綁定input元素的input事件
  • <input type="text" v-model="textVal"/> <!-- 等同于 --> <input type="text" v-bind:value="textVal" v-on:input="textVal = $event.target.value"/>

    本地存儲

    localStorage永久存儲

    語法:

    // 添加數據;setItem的value值是字符串類型的數據 先對數組或對象進行字符串轉換------JSON.stringify(數組或對象);localStorage.setItem('name','張三')// 獲取數據 取值如果是對象,數組字符串的,那么要進行轉換,JSON.parse例子:let time = localStorage.getItem('time');console.log(JSON.parse(time));localStorage.getItem('name'); // 張三// 刪除(time)某一項數據的值 localStorage.removeItem('time')// 清空 localStorage.clear();

    注意事項:

  • 永久存儲的,除非是主動刪除,不然是不會自動刪除的;刪除瀏覽器不會被刪除,刪除只能調用clear方法
  • 一般瀏覽器存儲的大小是5M
  • 存儲的值必須是字符串(先對數組,對象進行字符串轉換,JSON.stringify)
  • 5M = 1024 * 5kb

    sessionStorage臨時會話存儲

    語法:

    // 添加數據;setItem的value值是字符串類型的數據 存儲的值必須是字符串(先對數組,對象進行字符串轉換,JSON.stringify) JSON.stringify(數組或對象);sessionStorage.setItem('name','張三')// 獲取數據 取值如果是對象,數組字符串的,那么要進行轉換,JSON.parse例子:let time = localStorage.getItem('time');console.log(JSON.parse(time)); sessionStorage.getItem('name'); // 張三// 刪除(time)某一項數據的值 sessionStorage.removeItem('time')// 清空 sessionStorage.clear();

    注意事項:

  • 臨時存儲,關閉瀏覽器會自動清空數據
  • 一般瀏覽器存儲的大小是5M
  • cookie

    網站中,http請求是無狀態的。也就是第一次登陸成功(發送請求),第二次請求服務器依然不知道是哪一個用戶。這時候的cookie就是解決這個問題的,第一次登陸后服務器返回數據(cookie)給瀏覽器,然后瀏覽器保存在本地,當該用戶發送第二次請求,瀏覽器自動會把上次請求存儲的cookie數據自動帶上給服務器,服務器根據客戶端的cookie來判斷當前是哪一個用戶。cookie存儲有大小限制,不同瀏覽器不一樣,一般是4kb,所以cookie只能存儲小量數據。

    token: 用戶登錄憑證,服務端返回給瀏覽器(前后端分離項目,基本都是發送ajax請求)

    session

    session和cookie的作用有點類似,也是存儲用戶相關信息。不同的是cookie存儲在瀏覽器,而session存儲在服務器。

    Vue過濾器

    語法:

    過濾器 filters: {函數 toFix2(price參數變量名) {return price.toFixed(2)(toFixed 把數字轉換為字符串,結果的小數點后有指定位數的數字)(用法:toFixed() 方法可把 Number 四舍五入為指定小數位數的數字。)},}

    Vue指令

    深入雙向數據綁定原理

    vue雙向數據綁定原理:

    借助Object.defineProperty()對數據進行劫持,并結合發布-訂閱者模式,來實現雙向數據綁定

    vue的雙向數據綁定原理是什么?

    vue數據雙向綁定是通過數據劫持結合“發布者-訂閱者模式”的方式來實現的。
    vue是通過Object.defineProperty()來實現數據劫持,其中會有getter()和setter方法;當讀取屬性值時,就會觸發getter()方法,在view中如果數據發生了變化,就會通過Object.defineProperty()對屬性設置一個setter函數,當數據改變了就會來觸發這個函數;

    語法:

    Object.defineProperty(obj, prop, desc)1. `obj` 需要定義屬性的當前對象 2. `prop` 當前需要定義的屬性名 3. `desc` 屬性描述符

    數據屬性:

    通過Object.defineProperty()為對象定義屬性,有兩種形式,分別為數據描述符,存取描述符,下面分別描述兩者的區別:

  • value 表示它的默認值
  • writable 如果為true標識可以被修改,如果為false標識不能被修改(默認值為false)
  • configurable 描述屬性是否配置,以及可否刪除,可以認為是總開關 默認值 false(不可刪除)
  • enumerable 描述屬性是否出現在for in 或者 Object.keys()的遍歷中 默認值false(不能遍歷)
  • 例子:

    var p = {};// defineProperty(對象, 屬性名, {value: 值}) === p.name = '張三'Object.defineProperty(p, 'name', {value: '張三',writable: true, // writable: 設置屬性(name)是否可以修改,默認值: false(不可修改),true(可以修改)configurable: true, // configurable: 控制屬性是否可以刪除,默認值:false(不可以刪除), true(可以刪除)enumerable: true, // enumerable: 控制屬性是否可以被遍歷,默認值:false(不可以遍歷), true(可以遍歷)})console.log(p.name);p.name = '李四'//不可以直接修改,要先設置屬性console.log(p.name);// delete p.name;//不可以直接刪除,要先設置屬性// console.log(p);for (let key in p) {console.log(key)//不可以直接遍歷,要先設置屬性}另一種方法:let num = 0;// 定義p對象上age屬性; get和set方法分別對age屬性的獲取和賦值進行攔截,get方法的返回值就是age屬性對應的值Object.defineProperty(p, 'age', {// value: 20,get() {//監聽讀取操作獲取數據的時候 本身是沒有值的 值是有另外一個函數 return 出來的get就是在讀取name屬性這個值觸發的函數console.log('age上的get方法')// document.getElementById()return num;},set(val) {//監聽寫入操作改變數據的時候 進入的set 里面set就是在設置name屬性這個值觸發的函數num += (val + 100)console.log('age上的set方法', val)}})p.age = 30;console.log(p.age);

    自定義指令

    除了一些內置的制定(v-model和v-show…),Vue也允許注冊自定義指令。

    全局自定義指令格式:

    // 注冊一個全局自定義指令 v-demo Vue.directive('demo(指定名)', {inserted: function (el, binding) {console.log(el, binding);},update(el, binding){} })

    局部指令

    // 組件中注冊局部指令 new Vue({el: '#app',data: {},directives: {demo(指令名): {bind(el, binding){},inserted: function (el, binding) {cosnole.log(el, binding);},update(el, binding){},}} })

    鉤子函數:

    一個指令定義對象可以提供如下幾個鉤子函數 (均為可選):

    • bind:只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置。
    • inserted:被綁定元素插入父節點時調用 (僅保證父節點存在,但不一定已被插入文檔中)。
    • update:所在組件的 VNode 更新時調用,但是可能發生在其子 VNode 更新之前。指令的值可能發生了改變,也可能沒有。

    參數:

    • el:指令所綁定的元素,可以用來直接操作 DOM 。
    • binding:一個對象,包含以下屬性:
      • name:指令名,不包括 v- 前綴。
      • value:指令的綁定值,例如:v-demo="1 + 1" 中,綁定值為 2。
      • oldValue:指令綁定的前一個值
      • expression:字符串形式的指令表達式。例如 v--demo="1 + 1" 中,表達式為 "1 + 1"。
      • modifiers:一個包含修飾符的對象。例如:v-demo.foo.bar 中,修飾符對象為 { foo: true, bar: true }。

    Vue組件化開發

    組件化的思想

  • 如果我們實現一個頁面結構和邏輯非常復雜的頁面時,如果全部一起實現會變得非常復雜,而且也不利于后續的維護和迭代功能。
  • 但如果我們這時候把頁面分成一個個小的功能塊,每個功能塊能完成屬于自己這部分獨立的功能,那么整個頁面之后的維護和迭代也會變得非常容易。
  • 組件化開發的優勢:可維護性高 可復用性高

    組件化思想的應用開發:

  • 有了組件化的思想,我們在之后的開發中就要充分的利用它。
  • 盡可能的將頁面拆分成一個個小的、可復用的組件。
  • 這樣讓我們的代碼更加方便組織和管理,并且擴展性也更強。
  • 局部組件

    通過 Vue.component 方式注冊的組件,稱之為全局組件。任何地方都可以使用。全局注冊往往是不夠理想的。比如,如果你使用一個像 webpack 這樣的構建系統,全局注冊所有的組件意味著即便你已經不再使用一個組件了,它仍然會被包含在你最終的構建結果中。這造成了用戶下載的 JavaScript 的無謂的增加。

    <template id="tmp1"><!-- 組件必須只有一個根標簽 --><div><header>頭部 num: {{num}}</header><div>123</div></div></template>new Vue({el: "#app",components: {// key: 組件名稱, value: 組件內容aheader: {//任意命名//template標簽------實際上 元素是被當做一個不可見的包裹元素,主要用于分組的條件判斷和列表渲染。// 只能用這個標簽包裹template : '#tmp1',// 組件內的data必須是一個函數data() {return {num: 1}}}}})

    全局組件

    通過Vue CLI 進行Vue全局組件

    1、下載安裝包

    npm install -g @vue/cli # OR yarn global add @vue/cli

    2、檢查版本,并確認是否安裝成功

    vue --version

    3、如需升級全局的 Vue CLI 包,請運行:

    npm update -g @vue/cli# 或者 yarn global upgrade --latest @vue/cli

    4、創建一個項目

    vue create 自定義文件名(英文) 例如 vue create hello-world

    5、下載所需要的包工具

    會自動識別文件package-lock 里面所需要的工具包

    npm i

    6、開發模式運行

    npm run serve

    生產模式運行

    npm run build

    7、刪除項目

    del 文件名

    8、轉換文件夾名

    cd 文件路徑 例如: cd ./文件名

    9、清空

    cls 清空

    父組件和子組件

    組件和組件之間存在層級關系,而其中一種最重要的關系就是父子組件關系。

    data屬性必須是一個函數,而且函數返回一個對象 ,對象保存著數據

    data() {//函數return {//返回一個對象title: 'zujianbiaoti'}}

    為什么data在組件中必須是一個函數呢?

    原因是在于Vue讓每個組件對象都返回一個新的對象,因為如果是同一個對象的,組件在多次使用后會相互影響。

    父子組件間的通訊

    父級向子級傳遞

    在組件中,使用選項props來聲明需要從父級接收到的數據。

    props的值有兩種方式:

  • 字符串數組,數組中的字符串就是傳遞時的名稱。
  • 對象,對象可以設置傳遞時的類型(String,Number,Boolean,Array, Object,Date,Function,Symbol),也可以設置默認值等。
  • 父級 <名 :任意名 = 需要傳入子級的數據對象名></>子級props: {需要傳入子級的數據對象名(wrapperDate): {type: Object,default: {},//默認值required:false/true //必填,一定要傳值}三種寫法,另外另種一、props: {num: Number,}二、props :['num']然后子級就可以直接調用{{wrapperDate.cancelTxt}}

    子級向父級傳遞

    子組件向父組件傳遞數據,通過自定義事件

    子級 <div @click="函數名(submitFn)(參數)"></div>methods: {cancelFn(參數) {this.$emit("canceler自定義事件名" 參數);},},父級<Wrapper @canceler自定義事件名='fn函數名' :wrapperDate = 'textObj'></Wrapper>methods:{fn(){this.clickResult = this.textObj.cancelTxt},},

    多層父子組件之間的通訊

    例如祖父和孫子之間或者更多層

    使用:Vue提供的更高階方法:provide/inject

    這對選項需要一起使用,以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,并在其上下游關系成立的時間里始終生效。

    provide:Object | () => Object inject:Array<string> | { [key: string]: string | Symbol | Object }provide 選項應該是一個對象或返回一個對象的函數。該對象包含可注入其子孫的 property。在該對象中你可以使用 ES2015 Symbols 作為 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的環境下可工作。inject 選項應該是:一個字符串數組,或 一個對象,對象的 key 是本地的綁定名,value 是: 在可用的注入內容中搜索用的 key (字符串或 Symbol),或 一個對象,該對象的: from property 是在可用的注入內容中搜索用的 key (字符串或 Symbol) default property 是降級情況下使用的 value 提示:provide 和 inject 綁定并不是可響應的。這是刻意為之的。然而,如果你傳入了一個可監聽的對象,那么其對象的 property 還是可響應的。具體用法: // 父級組件提供 'foo' var Provider = {provide: {foo: 'bar'},// ... }// 子組件注入 'foo' var Child = {inject: ['foo'],created () {console.log(this.foo) // => "bar"}// ... }

    兄弟組件間的傳遞

    方法一:bus

    EventBus中央事件總線

    1、新建一個bus.js的文件,在文件中寫入

    import Vue from 'vue' export default new Vue

    2、在需要進行操作的組件中,引入bus.js

    import bus from "../../bus/bus"

    3、傳參的組件

    事件showFn() {//用bus.$emit(第一個參數代表事件名稱,第二個參數代表需要傳過去的參數,第二個參數代表需要傳過去的第二個參數……可以傳入多個參數)bus.$emit("showninfo", this.showin);},

    4、接收參數的組件

    通過$on監聽事件。//掛載mounted(){bus.$on('showninfo',val=>{console.log(val);this.showuin = val})

    this.bus.emit和this.bus.emit 和this.bus.emitthis.bus.on來進行跨組件通信了

    方法二:Vuex 提供的功能

    變更vuex中的數據或者狀態 this.$store.commit('increment') 第一個是方法名,第二個是參數拿到vuex中的數據 訪問數據用:$store methods: {increment() {this.$store.commit('increment')console.log(this.$store.state.count)} }通常放到計算屬性中computed: {count () {return this.$store.state.count}} }

    方法三:v-model

    v-model 的本質就是綁定一個屬性和事件

    // 父組件 <aa class="abc" v-model="test" ></aa> // aa子組件實現一: <template><div><ul><li>{{'里面的值:'+ msg}}</li><button @click="fn2">里面改變外面</button></ul></div> </template><script>export default {model: { // 使用modelprop: 'msg', //prop屬性將msg作為該組件被使用時(此處為aa組件被父組件調用)v-model能取到的值,event: 'cc' // event中的cc就是父組件上的自定義事件,用來更新父組件上的test值},props: {msg: ''},methods: {fn2 () {this.$emit('cc', this.msg+2)}}} </script>// aa子組件實現方法二: <template><div><ul><li>{{'里面的值:'+ value}}</li> // value會被賦值為v-model綁定的test的值。<button @click="fn2">里面改變外面</button></ul></div> </template><script>export default {props: {value: { // 必須要使用valuedefault: '',},},methods: {fn2 () {this.$emit('input', this.value+2) // 這兒必須用input 發送數據,發送的數據會被父級v-model=“test”接受到,再被value=test傳回來。}}}

    插槽slot

    為什么要使用插槽?

    slot翻譯為插槽,組件的插槽:

  • 組件的插槽也是為了讓我們封裝的組件更加具有擴展性。
  • 讓使用者可以決定組件內容的一些內容到底展示什么。
  • 如何封裝合適呢?抽取共性,保留不同

  • 最好的封裝方式就是將共性抽取到組件中,將不同暴露為插槽。
  • 一旦我們預留了插槽,就可以讓使用者根據自己的需求,決定插槽中插入什么內容。
  • 是搜索框,還是文字,還是菜單。由調用者自己來決定。
  • 匿名插槽

    如何使用slot?

  • 在子組件中,使用特殊的元素<slot>就可以為子組件開啟一個插槽。
  • 該插槽插入什么內容取決于父組件如何使用。
  • 使用 <slot>我是插槽中的默認內容!!</slot> <Todolist>被替換的內容</Todolist>父組件<Todolist><a href="javascript:;" class="del" @click="reMove(idx)">刪除</a></Todolist>子組件<slot></slot>當組件渲染的時候,<slot></slot> 將會被替換為“a標簽”(<Todolist>標簽里面的內容)。插槽內可以包含任何模板代碼,包括 HTML:

    具名插槽

    當子組件的功能復雜時,子組件的插槽可能并非是一個。

  • 比如我們封裝一個導航欄的子組件,可能就需要三個插槽,分別代表左邊、中間、右邊。
  • 那么,外面在給插槽插入內容時,如何區分插入的是哪一個呢?
  • 這個時候,我們就需要給插槽起一個名字
  • 如何使用具名插槽呢?

  • 非常簡單,只要給slot元素一個name屬性即可
  • <slot name='myslot'></slot>
  • 父組件<Todolist>//用<template></template>標簽將內容包起來,并在標簽上使用 v-slot 指令,并以 v-slot 的參數的形式提供其名稱,向具名插槽提供內容。<template v-slot:btn><a href="javascript:;" class="del" @click="reMove(idx)">刪除</a></template></Todolist>子組件<slot name="btn"></slot>當組件渲染的時候,name相等的 <slot></slot> 將會被替換為“a標簽”(<Todolist>標簽里面的內容)。插槽內可以包含任何模板代碼,包括 HTML:任何沒有被包裹在帶有 v-slot 的 <template> 中的內容都會被視為默認插槽的內容。注意 v-slot 只能添加在 <template> 上(有一種情況例外)

    作用域插槽

    默認情況下,父組件使用子組件,插槽數據默認是拿父組件的數據,而不是子組件拿數據。

    作用域插槽在父組件使用我們的子組件時, 插槽的數據從子組件中拿到數據,而不是從父組件拿到。

    ? 作用域插槽,作用:可以拿到子組件slot標簽上自定義屬性的集合

    父組件<Todolist><template v-slot:btn={idx}><a href="javascript:;" class="del" @click="reMove(idx)">刪除</a></template></Todolist>子組件<template v-slot:default="{$index}"><slot name="btn" :idx="$index"></slot></template>{idx}是Es6的解構語法$index 自定義的命名default意思是默認,下一個子組件不需要給name屬性,直接可以渲染替換<slot></slot>里面的內容孫子組件<slot :$index="i"></slot>當組件渲染的時候,<slot></slot> 將會被替換為“a標簽”(<Todolist>標簽里面的內容)。插槽內可以包含任何模板代碼,包括 HTML

    多種寫法

    // 1、基本寫法 <one-comp><button slot="btn" slot-scope="scope">按鈕{{scope.msg}}</button> </one-comp>// 2、基本寫法之模板寫法 <one-comp><template slot="btn" slot-scope="scope"><button>按鈕{{scope.msg}}</button></template> </one-comp>// 3、指令寫法 <one-comp v-slot:btn="scope"><button>按鈕{{scope.msg}}</button> </one-comp>// 4、指令寫法之模板寫法 <one-comp><template v-slot:btn="scope"><button>按鈕{{scope.msg}}</button></template> </one-comp>

    FileZilla

    FileZilla是一個免費開源的FTP軟件,分為客戶端版本和服務器版本

    Webpack

    Webpack(自動化 模塊化 前端開發構建工具)

    1. gulp和webpack

    Gulp側重于前端開發的 整個過程 的控制管理(像是流水線),我們可以通過給gulp配置不同的task(通過Gulp中的gulp.task()方法配置,比如啟動server、sass/less預編譯、文件的合并壓縮等等)來讓gulp實現不同的功能,從而構建整個前端開發流程。

    1. 生成項目依賴文件

    // 執行后生成package.json文件 npm init -y

    2. 安裝依賴(node環境在12.10.0下!)

    nvm install 12.10.0

    nvm use 12.10.0

    npm i webpack@4.44.1 webpack-cli@3.3.12 -g

    // 最后的參數-D是安裝到package.json的開發依賴devDependencies(開發環境)對象里,也可以用 --save-dev代替 npm install webpack@4.44.1 webpack-cli@3.3.12 -D// 全局安裝webpack和webpack-cli npm i webpack@4.44.1 webpack-cli@3.3.12 -g// -S是--save的簡寫,這樣安裝的話,會安裝到dependencies(生產環境)對象里,也可以用 --save代替 npm install jquery -S // package.json {"name": "webpack-demo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"author": "","license": "ISC","devDependencies": {"webpack": "^4.40.2","webpack-cli": "^3.3.9"},"dependencies": {"jquery": "^3.4.1"} }

    devDependencies與dependencies的區別:

    在發布npm包的時候,本身dependencies下的模塊會作為依賴,一起被下載;devDependencies下面的模塊就不會自動下載了;但對于項目而言,npm install 會自動下載devDependencies和dependencies下面的模塊。

    3.創建入口文件

    `index.html`引入js文件:<script src="./index.js"></script>js文件import $ from 'jquery' $('ul li:even').css({background: 'red'}) $('ul li:odd').css({background: 'green'})

    瀏覽器打開會出現報錯,因為瀏覽器并不兼容import引入模塊這種方式,所以我們要用到webpack打包

    4、通過webpack打包

    // 執行命令 output輸出 webpack index.js -o dist/bundle.js

    出現 “無法將webpack 識別為……的報錯

    出現這個報錯,這是因為命令行執行時候會找全局的webpack,但是我們并沒有安裝全局的webpack,所以我們可以安裝全局webpack,或者是使用腳本方式啟動

    執行package.json文件中添加的start命令

    {"name": "webpack-demo","version": "1.0.0","description": "","main": "index.js","scripts": {"start": "webpack index.js -o dist/bundle.js"},"author": "","license": "ISC","devDependencies": {"webpack": "^4.40.2","webpack-cli": "^3.3.9"},"dependencies": {"jquery": "^3.4.1"} }

    跑一下

    // 生成 dist文件夾和bundle.js文件 npm run start

    然后再把index.html原來引入index.js的地方改成是通過webpack生成的bundle.js

    <!--index.html文件--> <!--<script src="./index.js"></script>--> <script src="./dist/bundle.js"></script>

    在根目錄里,建立webpack.config.js:

    const path = require('path');module.exports = {entry: path.join(__dirname, './index.js'), // dirname代表索引到文件所在目錄output: {path: path.join(__dirname, './dist'),filename: 'bundle.js'} }

    package.json:

    文件修改命令

    "scripts": {"start": "webpack --config webpack.config.js"}

    webpack-dev-server

    這時候如果修改index.html的背景顏色red改成是gray,會發現瀏覽器刷新也沒有效果,需要再跑一次npm run start命令才有用,這時候就需要webpack-dev-server(熱重載)

    安裝:

    npm install webpack-dev-server@3.11.2 -D

    package.json:

    "scripts": {"start": "webpack-dev-server --config webpack.config.js --open --port 3002 --hot"} // --open 自動打開瀏覽器 // --port 服務監聽的端口 3002 // --hot 自動更新

    html-webpack-plugin

    安裝:npm install html-webpack-plugin@4.5.1 -D

    webpack.config.js

    const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: path.join(__dirname, './index.js'),output: {path: path.join(__dirname, './dist'),filename: 'bundle.js'},plugins: [new HtmlWebpackPlugin({template: path.join(__dirname, './index.html'),filename: 'index.html'})] }

    刪掉index.html文件里面的bundle.js引用,因為html-webpack-plugin會自動把打包出來的bundle自動加到我們的index.html代碼里

    因為webpack默認是不識別.css文件的,需要我們通過 loader 將 .css 文件進行解釋成正確的模塊。

    安裝css-loader和style-loader

    npm install css-loader@5.2.4 style-loader@2.0.0 -D //index.css -> bundle.js -> style-loader -> <style> index.html // css-loader的作用是將index.css文件解析為webpack能識別的模塊,然后打包進bundle.js里面,但是這樣樣式并未成功顯示在瀏覽器中。 // style-loader的作用就是將打包到bundle.js中的樣式綁定到瀏覽器上,以style標簽的形式顯示出來

    webpack.config.js

    const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: path.join(__dirname, './index.js'),output: {path: path.join(__dirname, './dist'),filename: 'bundle.js'},plugins: [new HtmlWebpackPlugin({template: path.join(__dirname, './index.html'),filename: 'index.html'})],module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader'] // 注意:這里的數組是反向讀取的(即從右往左)}]} }

    補充:引入的文件是less

    安裝:npm install less-loader@7.2.1 less@4.1.0 -D

    規則:

    {

    ? test: /.less$/,

    ? use: [‘style-loader’, ‘css-loader’, ‘less-loader’]

    }

    ES6 轉 ES5

    安裝依賴包

    npm install babel-core babel-loader@7.1.5 babel-plugin-transform-runtime@6.23.0 babel-preset-env@1.7.0 babel-preset-stage-0@6.24.1 -D

    html熱更新

    在安裝過html-webpack-plugin之后,安裝:

    npm install --save-dev raw-loader@4.0.2

    在webpack.config.js中配置raw-loader:

    module.exports = {......module: {rules: [{test: /\.(htm|html)$/,use: ['raw-loader']},......]} }

    在 index.js 中引入html:

    import './index.html'

    Vue CLI腳手架

    Vue CLI 是一個基于 Vue.js 進行快速開發的完整系統,提供:

    • 通過 @vue/cli 實現的交互式的項目腳手架。

    • 通過 @vue/cli + @vue/cli-service-global 實現的零配置原型開發。

    • 一個運行時依賴 (

      @vue/cli-service

      ),該依賴:

      • 可升級;
      • 基于 webpack 構建,并帶有合理的默認配置;
      • 可以通過項目內的配置文件進行配置;
      • 可以通過插件進行擴展。
    • 一個豐富的官方插件集合,集成了前端生態中最好的工具。

    • 一套完全圖形化的創建和管理 Vue.js 項目的用戶界面。

    **安裝Vue CLI腳手架的包

    npm install -g @vue/cli # OR yarn global add @vue/cli

    檢查版本

    安裝成功之后,可以用這個命令來檢查其版本是否正確 (4.x):

    vue --version vue -V

    如果安裝比較慢,可以把下載源切換成淘寶的源:

    npm 對應的淘寶下載源設置:

    //切換taobao鏡像源 npm config set registry https://registry.npm.taobao.org/ // 查看下載源 npm config get registry

    yarn 對應的淘寶下載源設置:

    //切換taobao鏡像源 yarn config set registry https://registry.npm.taobao.org/// 查看下載源 yarn config get registry

    創建項目

    初始化項目

    vue create

    運行以下命令來創建一個新項目:

    vue create 文件名 例如 vue create hello-world 會自動新生成一個文件

    可以選擇手動模式生成

    對于每一項的功能,此處做個簡單描述:

    • TypeScript 支持使用 TypeScript 書寫源碼。
    • Progressive Web App (PWA) Support PWA支持
    • Router 路由
      Vuex 狀態管理
      CSS Pre-processors 支持 CSS 預處理器。
      Linter / Formatter 支持代碼風格檢查和格式化。
      Unit Testing 支持單元測試。
      E2E Testing 支持 E2E 測試。

    vue.config.js

    vue.config.js 是一個可選的配置文件,如果項目的 (和 package.json 同級的) 根目錄中存在這個文件,那么它會被 @vue/cli-service 自動加載。你也可以使用 package.json 中的 vue 字段,但是注意這種寫法需要你嚴格遵照 JSON 的格式來寫。

    這個文件應該導出一個包含了選項的對象:

    // vue.config.js module.exports = {// 選項...(例如:)lintOnSave: false // 關閉eslint }

    靜態資源參考:

    HTML和靜態資源

    預處理器 (Sass/Less/Stylus):

    如果當時沒有選好,內置的 webpack 仍然會被預配置為可以完成所有的處理。你也可以手動安裝相應的 webpack loader

    # Sass npm install -D sass-loader sass# Less npm install -D less-loader less# Stylus npm install -D stylus-loader stylus 1、需要先額外安裝一個全局的擴展 npm install -g @vue/cli-service-global

    環境

    開發環境

    生產環境

    預生產環境

    測試環境

    打包部署

    npm run build多了個dist目錄文件夾(html css,js)

    部署

    上傳本地的dist文件夾到服務器

    使用FileZilla

    1、新建站點,選擇SETP協議

    報錯404,可能文件路徑出現問題了(加個.就好了)

    安裝瀏覽器插件Vue-Devtools

    Vue-Devtools是vue在做項目開發時常用的瀏覽器插件。

    安裝

    • 點擊瀏覽器右上角的 三個點 ,在 更多工具 中,選擇 擴展程序
    • 打開 擴展程序 的 開發者模式
    • 將 Vue.js Devtools_5.3.3.crx 這個插件直接拽入當前界面,即可完成安裝

    常用修飾符

    vue中常用的修飾符分三種,分別是事件修飾符、按鍵修飾符和表單修飾符。

    1、事件修飾符

    • .stop 阻止事件冒泡(*)
    • .prevent 阻止默認事件(*)
    • .prevent.stop 阻止默認事件的同時阻止冒泡
    • .once 阻止事件重復觸發(once與stop不能一起使用,否則再次觸發事件,依然會冒泡)(*)

    語法: @click.stop.prevent = “事件名”

    <template><div><div class="big" @click="cb"><div class="small" @click="cs"><a href="#" @click.stop.prevent="ca">a標簽</a></div></div><button @click.once="cc">點我</button></div> </template><script> export default {methods:{cb(){console.log("點擊大的");},cs(){console.log("點擊小的");},ca(){console.log("點擊a標簽");},cc(){console.log("點擊按鈕");}}} </script><style> .big{width: 300px;height: 300px;background-color: pink; } .small{width: 200px;height: 200px;background-color: skyblue; } </style>

    2、按鍵修飾符

    在監聽鍵盤事件時,我們經常需要檢查詳細的按鍵。Vue 允許為 v-on 在監聽鍵盤事件時添加按鍵修飾符:

    <input v-on:keyup.enter="submit"> <input v-on:keyup.13="submit">

    3、表單修飾符

    表單上常用的 trim 和 number :

    想去除用戶輸入的前后空格:

    <input v-model.trim="val" type="text">

    希望在input的change之后再更新輸入框的值

    <input v-model.lazy="val" type="text">

    .trim與.lazy可以合并使用:

    二者沒有先后順序

    <template> <!-- 表單修飾符 --><div><!-- 加了.trim之后,獲取到的是去除前后空格的結果 --><input type="text" v-model.trim="iptVal"><button @click="handleClcik">按鈕</button><br><!-- 加了.number之后, 獲取到的用戶輸入的信息就是number類型了--><input type="number" v-model.number="numVal"><button @click="handleClcik2">按鈕</button><br><br><!-- 加了.lazy, 用戶每一次觸發就不會馬上更新這個值,等到用戶按回車的時候,才更新這個值 --><input type="text" v-model.lazy="ipt2Val"><p>{{ipt2Val}}</p></div> </template>

    Watch

    watch的作用可以監控一個值的變換,并調用因為變化需要執行的方法。可以通過watch動態改變關聯的狀態。

    簡單點說,就是實時監聽某個數據的變化。

    普通監聽

    <input type="text" v-model="msg"><h3>{{msg}}</h3>watch: {msg(val, oldVal){console.log(val, oldVal)}}跟data 同級

    立即監聽

    如果我們需要在最初綁定值的時候也執行函數,則就需要用到immediate屬性。

    <input type="text" v-model="num">跟data 同級watch: { 監聽變化的數據名num: {handler(val, oldVal) {console.log(val, oldVal);},// 組件注入頁面時就立即監聽immediate: true}}

    immediate需要搭配handler一起使用,其在最初綁定時,調用的函數也就是這個handler函數。

    深度監聽

    當需要監聽一個對象的改變時,普通的watch方法無法監聽到對象內部屬性的改變,只有data中的數據才能夠監聽到變化,此時就需要deep屬性對對象進行深度監聽。

    <h3>{{obj.age}}</h3><script> export default {name: 'Home',data(){return {obj: {name: "Lucy",age: 13}}},methods: {btnClick(){this.obj.age = 33;}},watch: {obj: {handler(val, oldVal){console.log(val.age, oldVal.age) // 33 33},deep: true}} } </script>

    注意:

    1、如果監聽的數據是一個對象,那么 immediate: true失效;

    2、一般使用于對引用類型的監聽,深度監聽,如監聽一個Object,只要Object里面的任何一個字段發生變化都會被監聽,但是比較消耗性能,根據需求使用,能不用則不用。

    3、因為上面代碼obj是引用數據類型,val, oldVal指向一致,導致看到的結果一樣。

    deep優化

    我們可以通過點語法獲取對象中的屬性,然后轉為字符串,即是對深度監聽的優化

    <template><div class="home"><h3>{{obj.age}}</h3><button @click="btnClick">按鈕</button></div> </template><script> export default {name: "Home",data() {return {obj: {name: "Lucy",age: 13}};},methods: {btnClick() {this.obj.age = 33;}},watch: {// 通過點語法獲取對象中的屬性,然后轉為字符串,即是對深度監聽的優化"obj.age": {handler(val, oldVal) {console.log(val, oldVal);},deep: true,immediate: true, // 此時監聽的數據不是一個對象,可以使用immediate}} }; </script>

    Watch與Computed的區別

    • watch中的函數是不需要調用的,computed內部的函數調用的時候不需要加()
    • watch(屬性監聽),監聽的是屬性的變化,而computed(計算屬性),是通過計算而得來的數據
    • watch需要在數據變化時執行異步或開銷較大的操作時使用,而對于任何復雜邏輯或一個數據屬性,在它所依賴的屬性發生變化時,也要發生變化,這種情況下,我們最好使用計算屬性computed。
    • computed 屬性的結果會被緩存,且computed中的函數必須用return返回最終的結果
    • watch 一個對象,鍵是需要觀察的表達式,值是對應回調函數。主要用來監聽某些特定數據的變化,從而進行某些具體的業務邏輯操作;

    Watch與Computed的使用場景

    • computed

      • 當一個結果受多個屬性影響的時候就需要用到computed
      • 最典型的例子: 購物車商品結算的時候
    • watch

      • 當一個數據的變化需要有額外操作的時候就需要用watch
      • 搜索數據
    • 總結:

      • 一個值的結果受其他值的影響,用computed
      • 一個值的變化將時刻影響其他值,用watch

    Mixins混入

    mixins就是定義一部分公共的方法或者計算屬性,然后混入到各個組件中使用,方便管理與統一修改。同一個生命周期,混入對象會比組件的先執行。

    1、導出mixins

    在src下創建 mixins/index.js,寫入:

    export const MixinsFn = {created() { console.log("這是mixins觸發的created")} }

    2、引用mixins

    <template><div class="about"><h1>This is an about page</h1></div> </template> <script> import { MixinsFn } from '@/mixins/index.js' export default {created(){console.log("這是about觸發的created")},mixins: [MixinsFn] } </script>

    我們會發現,mixins中的created 比 about中的created 優先執行。

    ref與$refs

    vue中獲取頁面里的某個元素(標簽或組件),可以給它綁定ref屬性,有點類似于給它添加id名。

    1、簡單使用

    <template><div class="">//ref = '屬性名'//獲取 $refs.屬性名======獲取到標簽<h3 ref="title">{{msg}}</h3><button @click="btnclick">按鈕</button></div> </template><script> export default {data() {return {msg: "你好"};},methods: {btnclick() {console.log(this.$refs.title); // 得到h3標簽}} }; </script><style lang = "less" scoped> </style>

    2、子組件中的數據獲取及方法調用

    子組件:

    <template><div class=""><h4>{{num}}</h4></div> </template><script> export default {data() {return {num: 100};},methods: {subFn(){console.log('子組件中的方法')}} }; </script><style lang = "less" scoped> </style>

    父組件:

    <template><div class=""><Sub ref="sub" /><button @click="btnclick">按鈕</button></div> </template><script> import Sub from '../components/Sub' export default {methods: {btnclick() {//獲取子組件的屬性值和子組件的方法console.log(this.$refs.sub.num); // 100 this.$refs.sub.subFn(); // '子組件中的方法'}},components: {Sub} }; </script><style lang = "less" scoped> </style>

    獲取Dom節點

    <button @click="fnNum" ref="btn">獲取child組件的num</button>methods:{fn() {console.log(this.$refs.btn); //可以獲取Dom節點----<button @click="fnNum" ref="btn">獲取child組件的num</button>this.$refs.btn.innerText 可以獲取Dom節點的內容-----獲取child組件的num}, }

    vue生命周期

    什么是生命周期: 從Vue創建、運行、到銷毀期間,總是伴隨著各種各樣的事件,這些事件,統稱為生命周期。

    **生命周期鉤子函數:**就是生命周期事件的別名;

    初始

    **beforeCreate:**實例剛剛在內存中被創建出來,此時還沒有初始化 data 和 methods 屬性。

    **created:**實例已經在內存中創建好,此時 data和methods 已經創建好,此時還沒有開始編譯模板

    和 methods、data 是同級 初始beforeCreate() {console.log("1.1---------------beforeCreate");console.log(1.1, this.num, this.fn, document.getElementById("op"));},created() {console.log("1.2-------------created");console.log(1.2, this.num, this.fn, document.getElementById("op"));},掛載beforeMount() {console.log("2.1---------------beforeMount");console.log(2.1, this.num, this.fn, document.getElementById("op"));},mounted() {console.log("2.2-------------mounted");console.log(2.2, this.num, this.fn, document.getElementById("op"));},更新beforeUpdate(){ //視圖跟新之前console.log("3.1-------------beforeUpdate");console.log(3.1, this.num, this.$refs.myp.innerHTML);},updated(){ //視圖跟新之后console.log("3.2-------------updated");console.log(3.2, this.num, this.$refs.myp.innerHTML);},銷毀beforeDestory(){ },destoryed(){}

    keep-alive包含的組件是不需要再重新創建(Create)

    掛載

    **beforeMount:**此時已經完成了模板編譯,但是還沒有掛載到頁面中;

    **mounted:**這個時候已經把編譯好的模板掛載到頁面指定的容器里;

    beforeMount: data 的數據可以訪問和修改,而且此時的模板已經編譯好了,還沒有更新到頁面中

    mounted: 此時編譯的模板更新到頁面中了

    更新

    **beforeUpdate:**狀態更新之前執行此函數,此時的 data 中的數據是最新,但是界面上顯示的還是舊的,因為此時還沒有開始重新渲染DOM節點;

    **updated:**實例更新完畢之后調用此函數,此時data 中的狀態值和界面上顯示的數據,都已經完成了更新,界面已經被重新渲染好了;

    beforeUpdate: 此時修改輸入框的內容,data中的數據已經更新了,但是頁面上顯示的還是舊數據;

    **updated:**此時 data 的內容已經更新,頁面顯示的也是最新的數據。

    銷毀

    **beforeDestroy:**實例銷毀之前調用,在這一步,實例讓然完全可用。

    **destroyed:**實例銷毀后調用,調用后,Vue實例指向的所以東西會被解綁,所有的事件監聽器會被移除,所有的子實力也會被銷毀。

    銷毀聲明周期(使用keep-alive組件是不會觸發銷毀生命周期)

    活躍和不活躍

    要搭配keep-alive組件來使用

    // 從不活躍進入活躍狀態// activated() {// console.log('activated');// },// // 從活躍進入不活躍// deactivated() {// console.log('deactivated')// },

    Vue-router(路由)

    路由的概念

    簡單來說路由 就是用來跟后端服務器進行交互的一種方式,通過不同的路徑,來請求不 同的資源,請求不同的頁面是路由的其中一種功能。

    1.后端路由

    概念:根據不同的用戶的不同URL請求,發送到服務器以后返回不同的內容。
    本質:是URL請求地址與服務器資源之間的對應關系。

  • 后端渲染的好處,相對于發送ajax請求拿數據,可以提高首屏渲染的性能,也有利于SEO的優化;
  • 后端路由的缺點:
  • 另一種情況是前端開發人員如果要開發頁面, 需要通過PHP和Java等語言來編寫頁面代碼
  • 而且通常情況下HTML代碼和數據以及對應的邏輯會混在一起, 編寫和維護都是非常糟糕的事情
  • 2.前端路由

    概念:根據不同的用戶事件,顯示不同的頁面內容
    本質:用戶事件與事件處理函數之間的對應關系

    前后端分離階段:

    • 隨著Ajax的出現,有了前后端分離的開發模式;
    • 后端只提供API來返回數據(json,xml),前端通過Ajax獲取數據,并且可以通過JavaScript將數據渲染到頁面中
    • 這樣做最大的優點就是前后端責任的清晰, 后端專注于數據上, 前端專注于交互和可視化上
    • 并且當移動端(iOS/Android)出現后, 后端不需要進行任何處理, 依然使用之前的一套API即可
    • 目前很多的網站依然采用這種模式開發

    單頁面應用階段:

    • 其實SPA最主要的特點就是在前后端分離的基礎上加了一層前端路由
    • 也就是前端來維護一套路由規則

    前端路由的核心是什么呢?

    • 改變URL,但是頁面不進行整體的刷新

    前端路由規則

    URL的hash和HTML5的history模式

    1、hash模式

    在瀏覽器中符號“#”,#以及#后面的字符稱之為hash,用window.location.hash讀取; 特點:hash雖然在URL中,但不被包括在HTTP請求中;用來指導瀏覽器動作,對服務端安全無用,hash不會重加載頁面。 hash 模式下,僅 hash 符號之前的內容會被包含在請求中,如 http://www.xxx.com (opens new window),因此對于后端來說,即使沒有做到對路由的全覆蓋,也不會返回 404 錯誤。

    2、history模式

    history采用HTML5的新特性;且提供了兩個新方法:pushState(),replaceState()可以對瀏覽器歷史記錄棧進行修改,以及popState事件的監聽到狀態變更。 history 模式下,前端的 URL 必須和實際向后端發起請求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少對 /items/id 的路由處理,將返回 404 錯誤。Vue-Router 官網里如此描述:“不過這種模式要玩好,還需要后臺配置支持……所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。”

    //寫在導出模塊里面 export defaultexport default new VueRouter({routes,mode: 'hash'//還可以是 'history'//兩者區別: hash 后面跟著# 之后才是path值//http://192.168.6.170:8080/#/me http://192.168.6.170:8080/#/cart//history /后面才是path值//http://192.168.6.170:8080/cate http://192.168.6.170:8080/home })

    Vue-router基本使用

    目前前端流行的三大框架,都有自己的路由實現:

    • Angular的ngRouter
    • React的ReactRouter
    • Vue的vue-router

    vue-router是Vue的官方路由插件,它和Vue是深度集成的,適合用于構建單頁面應用 https://router.vuejs.org/zh/ 。

    vue-router是基于路由和組件的,路由用于設定訪問路徑, 將路徑和組件映射起來;在vue-router的單頁面應用中, 頁面的路徑的改變就是組件的切換.

    安裝:

    npm install vue-router

    一般項目中建議在cli創建項目時就直接選擇需要路由,并搭配history模式。

    選擇router 模式

    在index.js文件中,明確安裝模塊功能(并實例化)

    import Vue from 'vue' import VueRouter from 'vue-router'Vue.use(VueRouter)

    對index.js文件進行路由設置

    //導入模塊 import VueRouter from 'vue-router' import Vue from 'vue' // 導入路由對象 Vue.use(VueRouter) // 定義路由規則 const routes = [{path: '/',component: () => import('../views/index.vue') ,children:[//定義方法一:{path: '/', // 瀏覽器訪問//name的作用用于之后傳參獲取定義的名(此名是唯一)name: 'Home',component: Homechildren:[{path: 'cate',component: () => import('../views/cate.vue') // 路由懶加載}]},//定義方法二:{path: 'cate',component: () => import('../views/cate.vue') // 路由懶加載},{path: '/',redirect: '/cart' // 這就是路由的重定向,重新定義跳轉路徑},{path: 'cart', // 改成這個之后,原來的/就沒有對用的組件了component: () => import('../views/cart.vue') },{path: 'me',component: () => import('../views/Mehome.vue') },{path: '*', // 匹配所有剩余的路由,只要不是上面提及的頁面,全部跳轉到404頁面component: () => import('@/views/Page404.vue')}]},] // 創建路由實例 并導出 export default new VueRouter({// 路由模式mode: 'hash', // history hash// 路由規則(路由映射關系)routes, })

    懶加載的方式

    // 方式一: 結合Vue的異步組件和Webpack的代碼分析 const User = resolve => { require.ensure(['@/views/User.vue'], () => { resolve(require('@/views/User.vue')) }) };// 方式二: AMD寫法 const User = resolve => require(['@/views/User.vue'], resolve);// 方式三: 在ES6中, 我們可以有更加簡單的寫法來組織Vue異步組件和Webpack的代碼分割. const Home = () => import(/* webpackChunkName: "user" */ '../views/User.vue')

    路由跳轉方式

    使用 router-link 標簽來實現跳轉

    <div id="nav"><router-link to="/">Home</router-link> | //等同于a標簽的效果<router-link to="/user">User</router-link> </div>///跳轉之后,內容將替換<router-view/> //然后通過 `router-view` 來顯示頁面。`router-link` 最終會被渲染為a標簽。 <router-view/>

    router-link 默認會被解析為a標簽,如果想讓它轉換成其他的標簽,就需要添加tag屬性:

    <router-link tag="li" to="/user">User</router-link>

    此時,router-link 就被解析為li標簽。

    點擊跳轉到指定的頁面

    設置點擊事件 方法jumpToAbout() {push 在末尾添加 this.$router.push({ push里面寫的是對象// path: '/home'name: 'Home'name是在定義路由規則里面設置的,等同于 path的作用})簡寫: // 簡寫 this.$router.push('/user')

    除了push,還有

    go、 整數是前進,負數是后退

    forward、 前進

    back、 后退

    replace、替換----replace(新的訪問 例如 “/name”)

    這幾個來觸發不同情況的跳轉。

    router.push(location, onComplete?, onAbort?) router.push(location).then(onComplete).catch(onAbort) router.replace(location, onComplete?, onAbort?) router.replace(location).then(onComplete).catch(onAbort) router.go(n) router.back() router.forward()

    攜帶參數

    jumpFn(){this.$router.push({// path:""name:'About',攜帶的參數的方法名query:{id:123456,name:"張三"}})},在網頁上顯示:http://192.168.6.170:8080/cate?id=123456&name=張三在子組件中可以拿到 - 通過生命周期初始函數得到 然后可以放入data 之后可以直接調用export default {data(){return {id:null,name:null}},生命周期初始函數created(){console.log(this.$route.query);this.id = this.$route.query.idthis.name = this.$route.query.name}}

    使用params傳參

    使用params傳參,得到的結果與使用query傳參得到的結果有以下區別:

    this.$router.push({name: "User", params: {userId: 123}}) // http://localhost:8081/user/123 this.$router.push({name: "User", query: {userId: 123}}) // http://localhost:8081/?userId=123 在路由的js文件中:'/editbrand': {path: '/editbrand/:id', //品牌管理編輯name: 'editbrand',component: () =>import(/* webpackChunkName: "editbrand" */ '../views/editbrand/Editbrand.vue'),},組件中:this.$router.push({name:'editbrand',params:{id:row.id}})

    * 重調強調:

    編程式導航中,使用name進行路徑跳轉,攜帶參數可以通過params和query,其中query會將參數攜帶在導航路徑上,而使用path進行路徑跳轉,無法攜帶params,只能攜帶query。

    補充:

    params參數傳參寫法相當于在路徑直接添加:

    //App.vue中: this.$router.push('/user/12');// router/index.js中: path: '/user/:userId',// User.vue中: created(){console.log(this.$route.params.userId); // 獲取到用戶id12 }

    路由的重定向

    const routes = [{path: '/',redirect: '/home' // 這就是路由的重定向,重新定義跳轉路徑},{path: '/home', // 改成這個之后,原來的/就沒有對用的組件了component: () => import('@/views/Home.vue')},... ...{path: '*', // 匹配所有剩余的路由,只要不是上面提及的頁面,全部跳轉到404頁面component: () => import('@/views/Page404.vue')} ]

    vue-router 有幾種導航鉤子?

    1、全局守衛: router.beforeEach2、全局解析守衛: router.beforeResolve3、全局后置鉤子: router.afterEach4、路由獨享的守衛: beforeEnter5、組件內的守衛: beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave

    全局守衛

    router.beforeEach

    全局前置守衛

    導航或者路由被觸發時,全局前置守衛被調用,解析執行完成之后,導航再跳轉

    守衛是異步解析執行,此時導航在所有守衛 resolve 完之前一直處于 等待中

    注冊:全局前置守衛 const router = new VueRouter({ ... })router.beforeEach((to, from, next) => {// ... })接收三個參數 to: (去) Route: 即將要進入的目標 路由對象from: (來) Route: 當前導航正要離開的路由next : Function: 一定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。 一般會使用 next(): 進行管道中的下一個鉤子。next(): 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。next(false): 中斷當前的導航。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器后退按鈕),那么 URL 地址會重 置到 from 路由對應的地址。next('/') 或者 next({ path: '/' }): 跳轉到一個不同的地址。當前的導航被中斷,然后進行一個新的導航。你可以向 next 傳遞任意位置對象,且允許設置諸如 replace: true、name: 'home' 之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。next(error): (2.4.0+) 如果傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給router.onError() 注冊過的回調。

    全局解析守衛

    router.beforeResolve

    router.beforeResolve注冊方法和全局前置守衛一樣這和 router.beforeEach 類似,區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之后,解析守衛就被調用。

    全局后置鉤子

    router.afterEach

    這些鉤子不會接受 next 函數也不會改變導航本身

    注冊: router.afterEach((to, from) => {// ... })

    路由獨享的守衛

    beforeEnter

    可以在路由配置上直接定義 beforeEnter 守衛:const router = new VueRouter({routes: [{path: '/foo',component: Foo,beforeEnter: (to, from, next) => {// ...}}] }) 守衛與全局前置守衛的方法參數是一樣的。

    組件內的守衛

    beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave

    可以在路由組件內直接定義以下路由導航守衛:beforeRouteEnter beforeRouteUpdate (2.2 新增) beforeRouteLeaveconst Foo = {template: `...`,beforeRouteEnter(to, from, next) {// 在渲染該組件的對應路由被 confirm 前調用// 不!能!獲取組件實例 `this`// 因為當守衛執行前,組件實例還沒被創建//可以通過傳一個回調給 next來訪問組件實例。在導航被確認的時候執行回調,并且把組件實例作為回調方法的參數。//beforeRouteEnter 是支持給 next 傳遞回調的唯一守衛。對于 beforeRouteUpdate 和 beforeRouteLeave 來說,this 已經可用了,所以不支持傳遞回調,因為沒有必要了。},例如:beforeRouteEnter (to, from, next) {next(vm => {// 通過 `vm` 訪問組件實例})}beforeRouteUpdate(to, from, next) {// 在當前路由改變,但是該組件被復用時調用// 舉例來說,對于一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,// 由于會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用。// 可以訪問組件實例 `this`},beforeRouteLeave(to, from, next) {// 導航離開該組件的對應路由時調用// 可以訪問組件實例 `this`} }//這個離開守衛通常用來禁止用戶在還未保存修改前突然離開。該導航可以通過 next(false) 來取消。 beforeRouteLeave (to, from, next) {const answer = window.confirm('Do you really want to leave? you have unsaved changes!')if (answer) {next()} else {next(false)} }

    完整的導航解析流程

  • 導航被觸發。
  • 在失活的組件里調用 beforeRouteLeave 守衛。
  • 調用全局的 beforeEach 守衛。
  • 在重用的組件里調用 beforeRouteUpdate 守衛 (2.2+)。
  • 在路由配置里調用 beforeEnter。
  • 解析異步路由組件。
  • 在被激活的組件里調用 beforeRouteEnter。
  • 調用全局的 beforeResolve 守衛 (2.5+)。
  • 導航被確認。
  • 調用全局的 afterEach 鉤子。
  • 觸發 DOM 更新。
  • 調用 beforeRouteEnter 守衛中傳給 next 的回調函數,創建好的組件實例會作為回調函數的參數傳入。
  • $refs 和 $el的用法

    $refs

    $refs 一個對象,持有注冊過 ref attribute 的所有 DOM 元素和組件實例。 dom還沒有渲染完成,是不能通過ref調用dom的。加在普通元素上,獲取的是dom元素<div ref="system">測試</div> // 獲取 mounted() {console.log(this.$refs.system); }加在子組件上,獲取的是組件實例,可以使用組件的所有方法 // this.$ref.xxx.方法名() // 父組件 <contact-info ref="contactInfo"/> import ContactInfo from './ContactInfo' components: { ContactInfo }, mounted() {this.$refs.contactInfo.initVal(data) // 調用子組件方法 } // 子組件 methods: {initVal(data){Object.keys(this.contactInfo).forEach(val=>{this.contactInfo[val] = data[val]})} }具體使用: 組件內(元素內)設置 <div ref="自定義名稱"> </div>this.$refs 拿到 如果是組件實例,可以使用組件的所有方法 this.$refs.方法名

    $el

    $el Vue 實例使用的根 DOM 元素。 $el讀取的是組件實例掛載的dom元素// 子組件 <template><div>測試</div> </template> <script> export default {name: 'TestComs' }; </script>// 父組件<test ref="testCom" /><div ref="test">11</div>mounted() {console.log(this.$refs.testCom, '組件ref'); // 獲取組件實例console.log(this.$refs.testCom.$el, '組件el'); // 獲取組件實例的dom元素//獲得 <div> 測試 </div>console.log(this.$refs.test, '元素ref'); // 獲取dom元素//獲得<div ref="test">11</div>console.log(this.$refs.test.$el, '元素el'); // $el用于vue組件,普通dom元素不能用//獲得undefined},

    $set

    Vue中data中變量的數據值發生改變,界面沒有跟著更新,是什么原因(Vue數據雙向綁定失效)

    1.如果data里面定義了對象,對象里面的鍵值沒有,getter/setter函數沒法監聽到屬性值的數據變化,會導致此現象的發生。

    解決方法:

    Vue.set(obj, key, value); // or this.$set(obj, key, value);使用方法: 接收三個參數 this.$set(原數組或者原對象,索引值或者鍵值對名,需要賦的值)

    Vuex----store

    Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化。

    說得直白點,vuex就是vue.js中管理數據狀態的一個庫,通過創建一個集中的數據存儲,供程序中所有組件訪問。

    一個數據只要放在了vuex中,當前項目所有的組件都可以直接訪問這個數據。

    安裝;

    npm install vuex --save

    在store文件夾中的index.js中寫入

    //引入模塊 import Vue from 'vue' import Vuex from 'vuex'Vue.use(Vuex)//導出模塊 export default new Vuex.Store({state: {num: 0,uerinfo:{}},mutations: {increment (state,user) {state.uerinfo = user}} })

    在miain.js文件中引入store

    import store from './store'new Vue({router,store,render: h => h(App) }).$mount('#app')

    vuex有以下常用的幾個核心屬性概念:

    State

    • State

    (個人理解)存放數據的容器

    vuex中的state類似于data,用于存放數據,只不過這個數據是所有組件公用的。

    state: {數據,對象key : value值的方式num: 0,uerinfo:{}}, 組件中<template><div><h3>{{$store.state.num}}</h3></div> </template>也可以使用computed computed: {num(){return this.$store.state.num} }// 標簽中 <h3>{{num}}</h3>

    Getters

    • Getters

    vuex中的getters類似于computed計算屬性,getters的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。

    封裝異步操作

    import Vue from 'vue' import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {num: 2},getters: {// 這里的參數state可以讓我們快速獲取到倉庫中的數據doubleNum(state) { return state.num * 2;}} })組件中 <template><div><h3>{{num}}</h3></div> </template><script> export default {computed: {num(){return this.$store.getters.doubleNum}} }; </script>

    Mutations

    • Mutations

    個人理解:存放方法,然后此方法被別的組件調用

    更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。

    import Vue from 'vue' import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {num: 2},mutations: {// payload專業名稱為“載荷”,其實就是個參數addNum(state, payload) {state.num += payload;}} })調用的組件<template><div><h3>{{num}}</h3><button @click="btnClick">累加2</button></div> </template><script> export default {computed: {num(){return this.$store.state.num}},methods: {btnClick(){// 使用commit來觸發事件,第二個參數是要傳遞給payload的數據this.$store.commit('addNum', 2)}} }; </script>如:this.$store.commit('increment',uerRes.data)this.$store.commit('函數方法名',傳入的參數)并且它會接受 state 作為第一個參數

    Actions

    • Actions

    Action 類似于 mutation,不同在于:

    • Action 提交的是 mutation,而不是直接變更狀態。
    • Action 可以包含任意異步操作。
    import Vue from 'vue' import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {num: 2},mutations: {addNum(state, payload) {state.num += payload;}},actions: {// context是一個對象,包含了commit和stateAsyncAddNum(context,payload) { setTimeout(() => {context.commit('addNum', payload)}, 1000)}} })組件中 <template><div><h3>{{num}}</h3><button @click="btnClick">累加2</button></div> </template><script> export default {computed: {num(){return this.$store.state.num}},methods: {btnClick(){// dispatch是分發到意思,其實也是觸發Actions中的方法this.$store.dispatch('AsyncAddNum', 2)}} }; </script>

    當然,上面actions中的寫法有點累贅,我們還可以改寫:

    AsyncAddNum({ commit },payload) { setTimeout(() => {commit('addNum', payload)}, 1000) }// 如果你還想獲取state中的值,可以這樣: AsyncAddNum({ commit,state },payload) { console.log(state.num); // 2setTimeout(() => {commit('addNum', payload)}, 1000) }

    Modules

    • Modules

    把累加單獨抽出來作為一個模塊,在store下新建一個 add/index.js 文件:

    export default {namespaced: true, // 命名空間,為true時,可以在store中把當前模塊文件夾名稱(add),當作模塊名使用state: {num: 2},getters: {doubleNum(state) {return state.num * 1;}},mutations: {addNum(state, payload) {state.num += payload;}},actions: {AsyncAddNum({ commit }, payload) {setTimeout(() => {commit('addNum', payload)}, 300)}} }

    把有關累加的所有內容,都移動至本文件。再到原來倉庫index.js中的modules添加:

    引入存放模塊的文件 import add from './add'export default new Vuex.Store({...,modules: {add} })

    命名空間

    如果希望你的模塊具有更高的封裝度和復用性,你可以通過添加 namespaced: true 的方式使其成為帶命名空間的模塊。當模塊被注冊后,它的所有 getter、action 及 mutation 都會自動根據模塊注冊的路徑調整命名。

    const moduleA ={namespaced:true, //開啟namespace:true,該模塊就成為命名空間模塊了state:{count:10,countA:888},getters:{...},mutations:{...},actions:{...} }可以在單個模塊中通過添加namespaced:true的方式使其成為帶命名空間的模塊。組件中如何獲取帶有命名空間moduleA中的state數據? 1、基本方式:this.$store.state.moduleA.countA 2、mapState輔助函數方式:...mapState({count:state=>state.moduleB.countB}) 組件中調用命名空間模塊中的getters 共有三種方式,如下: //1. commonGetter(){this.$store.getters['moduleA/moduleAGetter'] }, //2. ...mapGetters('moduleA',['moduleAGetter']),此處的moduleA,不是以前綴的形式出現!!! //3.別名狀態下 ...mapGetters({paramGetter:'moduleA/moduleAGetter' }),組件中調用命名空間模塊中的Mutations 共有三種方式,如下: //1,3加個前綴moduleA/,都可以實現。2使用輔助函數未變名稱的特殊點!!! //1. commonMutation(){this.$store.commit('moduleA/moduleAMutation'); }, //2. ...mapMutations('moduleA',['moduleAMutation']), //3.別名狀態下 ...mapMutations({changeNameMutation:'moduleA/moduleAMutation' }),組件中調用命名空間模塊中的Actions(與mutations一致) 共有三種方式,如下: 1,3加個前綴moduleA/,都可以實現。2使用輔助函數未變名稱的特殊點!!! //1. commonAction(){this.$store.dispatch('moduleA/moduleAAction') }, //2. ...mapActions('moduleA',['moduleAAction']), //3.別名狀態下 ...mapActions({changeNameAction:'moduleA/moduleAAction' })在帶命名空間的模塊中,如何將action注冊為全局actions兩個條件:①添加 root: true②并將這個 action 的定義放在函數 handler 中//storeAction在命名空間moduleA中,但是它是一個全局actions const moduleA = {namespaced:true,storeAction:{root:true, //條件1handler(namespacedContext, payload){//條件2:handler//namespacedContext 上下文信息//payload 載荷,即參數console.log(namespacedContext)console.log(payload)alert("我是模塊A中的全局storeAction")}} }

    拆分寫法

    實際上我們可以把state、getter、mutation、action和module都抽離出來,這樣可以讓store文件看著更加簡潔。我們來將 store/index.js 進行拆分:

    state.js:

    export default {num1: 0,title: '標題' }

    mutations.js:

    export default {cutNum(state, payload) {state.num1 -= payload;} }

    actions.js:

    export default {AsyncCutNum({ commit }, payload) {setTimeout(() => {commit('cutNum', payload)}, 300)} }

    modules.js:

    import add from './add' export default {add }

    最后,在 store/index.js 中:

    import Vue from 'vue' import Vuex from 'vuex' import state from './state' import mutations from './mutations' import actions from './actions' import modules from './modules'Vue.use(Vuex)export default new Vuex.Store({state,mutations,actions,modules })

    輔助函數

    mapState

    當一個組件需要獲取多個狀態的時候,將這些狀態都聲明為計算屬性會有些重復和冗余。為了解決這個問題,我們可以使用 mapState 輔助函數幫助我們生成計算屬性,讓你少按幾次鍵:

    mapState 函數返回的是一個對象

    // 在單獨構建的版本中輔助函數為 Vuex.mapState import { mapState } from 'vuex'export default {// ...computed: mapState({// 箭頭函數可使代碼更簡練(方法一)count: state => state.count,// (方法二)傳字符串參數 'count' 等同于 `state => state.count`countAlias: 'count',// (方法三)為了能夠使用 `this` 獲取局部狀態,必須使用常規函數countPlusLocalState (state) {return state.count + this.localCount}}) }

    當映射的計算屬性的名稱與 state 的子節點名稱相同時,我們也可以給 mapState 傳一個字符串數組。

    computed: mapState([// 映射 this.count 為 store.state.count'count' ])

    mapState 函數返回的是一個對象

    我們需要使用一個工具函數將多個對象合并為一個,以使我們可以將最終對象傳給 computed 屬性。但是自從有了對象展開運算符 (opens new window),我們可以極大地簡化寫法:

    computed: {localComputed () { /* ... */ },// 使用對象展開運算符將此對象混入到外部對象中...mapState({// ...}) }

    mapGetters

    mapGetters 輔助函數僅僅是將 store 中的 getter 映射到局部計算屬性:

    import { mapGetters } from 'vuex'export default {// ...computed: {// 使用對象展開運算符將 getter 混入 computed 對象中...mapGetters(['doneTodosCount','anotherGetter',// ...])} }

    mapMutations

    import { mapMutations } from 'vuex'export default {// ...methods: {...mapMutations(['increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`// `mapMutations` 也支持載荷:'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`]),...mapMutations({add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`})} }

    mapActions

    import { mapActions } from 'vuex'export default {// ...methods: {...mapActions(['increment', // 將 `this.increment()` 映射為 `this.$store.dispatch('increment')`// `mapActions` 也支持載荷:'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.dispatch('incrementBy', amount)`]),...mapActions({add: 'increment' // 將 `this.add()` 映射為 `this.$store.dispatch('increment')`})} }

    內置組件

    keep-alive

    緩存加載

    作用:主要用于保留組件狀態或避免重新渲染。

    include 和 exclude prop 允許組件有條件地緩存。二者都可以用逗號分隔字符串、正則表達式或一個數組來表示:

    用在包裹著占位符,包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。<keep-alive exclude="Home"><router-view></router-view></keep-alive>include - 字符串或正則表達式。只有名稱匹配的組件會被緩存。exclude - 字符串或正則表達式。任何名稱匹配的組件都不會被緩存。max - 數字。最多可以緩存多少組件實例。給組件起名,以此來確定是需要操作那個組件export default {name:"Home",}逗號分隔字符串<keep-alive include="a,b">正則表達式 (使用 `v-bind`)<keep-alive :include="/a|b/">數組 (使用 `v-bind`)<keep-alive :include="['a', 'b']">

    最多可以緩存多少組件實例。一旦這個數字達到了,在新實例被創建之前,已緩存組件中最久沒有被訪問的實例會被銷毀掉。

    axios 訪問 API

    axios

    安裝

    npm install axiosyarn add axios

    引入模塊

    import axios from "axios"; import qs from "qs"讀取 JSON 數據 methods;{Fn(){axios.post('http://192.168.113.249:8081/cms/phoneRegin',{params: {ID: 12345}}}.then(res=>{}).catch(function (error) {console.log(error);});}方法二 // 直接在 URL 上添加參數 ID=12345 axios.get('/user?ID=12345').then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});請求頭axios.get('http://192.168.113.249:8081/cms/phoneRegin',{headers:{'x-auth-token':' '}post請求axios.post('https://www.runoob.com/try/ajax/demo_axios_post.php').then(response => (this.info = response)).catch(function (error) { // 請求失敗處理console.log(error);});}post請求 傳參說明 axios.post('/user', {firstName: 'Fred', // 參數 firstNamelastName: 'Flintstone' // 參數 lastName}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});

    qs

    qs 是一個增加了一些安全性的查詢字符串解析和序列化字符串的庫。

    用法之一:解析 URI 編碼

    qs.stringify({phone:this.username,password:this.pwd})

    項目

    初始化樣式

    <style lang="less" scoped>//在這里可以直接寫樣式或者引入less文件*scoped 樣式只作用于當前組件//.header{height: 50px;background-color: #333; } </style>

    安裝初始化樣式庫reset-css:

    npm i reset-css 或者 yarn add reset-css

    安裝成功后在main.js中引入即可:

    import "reset-css"

    網站數據請求模塊

    發送請求:

    安裝axios模塊: npm i axios

    嘗試在app.vue中做數據請求:

    import axios from "axios" export default {...created(){//get請求axios.get("http://192.168.113.249:8081/cms/products/recommend").then(res=>{console.log(res.data);}).catch(err=>{console.log(err);}) }, }

    代理配置:

    對 vue.config.js 進行配置:

    module.exports = {devServer: {port: 8080,proxy: {'/api': {target: "http://192.168.113.249:8081/cms",pathRewrite: {'^/api': ''}}}} }

    由于配置文件修改了,這里一定要記得重新 yarn serve?(跑一下)!!

    API與Request封裝

    在 src 下新建 request目錄 ,在request目錄下新建 request.js

    request.js 中:

    import axios from "axios"const instance = axios.create({baseURL:"http://192.168.113.249:8081/cms",timeout:5000 })instance.interceptors.request.use(config=>{console.log("每一次發起請求前,都會先執行這里的代碼");console.log(config); //config本次請求的配置信息return config },err=>{return Promise.reject(err) }) = instance.interceptors.response.use(res=>{console.log("每一次接收到響應,都會先執行這里的代碼,再去執行成功的那個回調函數then");return res },err=>{return Promise.reject(err) })export default instance

    為了更好地管理我們的這些接口,我們把所有請求都抽取出來在一個api.js中

    在request目錄下新建api.js,api.js 中:

    import request from './request'// 請求精品推薦數據 export const JingpinAPI = () => request.get('/products/recommend')

    如:

    request.js文件中

    import axios from 'axios';const instance = axios.create({timeout:15000,baseURL:'', })instance.interceptors.request.use((config)=>{const token = localStorage.getItem('token')//設置請求頭if(token){config.headers['X-Nideshop-Token'] = token}return config },(err)=>{return Promise.reject(err) })instance.interceptors.response.use((reset)=>{return reset.data; },(err)=>{return Promise.reject(err) })export default instance;

    api.js文件中

    import request from './request'; import qs from 'qs';//post請求 export const getUserByToken = (data)=>request.post('http://kumanxuan1.f3322.net:8360/admin/auth/getUserByToken',qs.stringify(data))//get請求 export const getGoods = (data)=>request.get('http://kumanxuan1.f3322.net:8360/admin/goods',{params:data})

    導航欄點擊之后的樣式顯示:

    <li :class="$route.path==='/home'?'active':''">首頁</li>三元表達式: true 執行前面的,false 執行后面的

    點擊之后設置路由跳轉

    <li @click="$router.push('/home')" :class="$route.path==='/home'?'active':''">首頁</li>

    拼圖驗證滑塊

    插件參考:https://gitee.com/monoplasty/vue-monoplasty-slide-verify

    安裝插件

    npm install --save vue-monoplasty-slide-verify 或者 yarn add vue-monoplasty-slide-verify

    main.js入口文件引中入

    import SlideVerify from 'vue-monoplasty-slide-verify' // 拼圖驗證碼Vue.use(SlideVerify)

    在組件中使用

    <template><slide-verify :l="42" :r="20" :w="362" :h="140" @success="onSuccess" @fail="onFail" @refresh="onRefresh" :style="{ width: '100%' }" class="slide-box" ref="slideBlock" :slider-text="msg"></slide-verify> </template><script> export default {data() {return {msg: "向右滑動"};},methods: {// 拼圖成功onSuccess(times) {let ms = (times / 1000).toFixed(1);this.msg = "login success, 耗時 " + ms + "s";},// 拼圖失敗onFail() {this.onRefresh(); // 重新刷新拼圖},// 拼圖刷新onRefresh() {this.msg = "再試一次";},}, }; </script><style lang="less" scoped> /deep/.slide-box {width: 100%;position: relative;box-sizing: border-box;canvas {position: absolute;left: 0;top: -120px;display: none;width: 100%;box-sizing: border-box;}.slide-verify-block{width: 85px;height: 136px;}.slide-verify-refresh-icon {top: -120px;display: none;}&:hover {canvas {display: block;}.slide-verify-refresh-icon {display: block;}} } </style>

    點擊獲取驗證碼按鈕的邏輯

    可以正常獲取驗證碼的前提是:手機號格式正確

    所以,點擊獲取驗證碼的邏輯如下:

    1、如果校驗手機號格式不正確,則return

    2、滑塊拼圖驗證不通過,則return

    3、驗證成功后,發起請求,獲取驗證碼成功,則進行倒計時

    【百度】結合運營商之后的手機號碼的正則:

    /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/ <div class="btn checkcode-btn" @click="getCode">獲取驗證碼</div> ... <script>getCode(){// 1、驗證手機號是否正確if(!/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/.test(this.phoneNum)){alert("請輸入正確的手機號");this.$refs.phone.focus();return} alert("手機號格式正確");// 2、進行滑塊驗證// 3、驗證成功后,發起請求,獲取驗證碼成功,則進行倒計時,并展示秒數},</script>

    倒計時及其展示

    <div class="btn checkcode-btn" @click="getCode"><span v-show="!isShowCount">獲取驗證碼</span><span v-show="isShowCount">{{count}} s</span> </div> <script>methods:{countdown(){// 計時的方法// 倒計時,實際上就是每隔1秒,count減去1// 每次點擊先讓count為60this.count=60;let timer = null;timer = setInterval(()=>{this.count--if(this.count===0){// 清除定時器 clearInterval(timer)}},1000);},getCode(){// 1、驗證手機號是否正確/* if(!/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/.test(this.phoneNum)){alert("請輸入正確的手機號");this.$refs.phone.focus();return} */// 2、進行滑塊驗證if (this.msg == "再試一次" || this.msg == "向右滑動") {alert("請先進行滑塊驗證");return }// 3、驗證成功后,發起請求,獲取驗證碼成功,則進行倒計時,并展示秒數// 這里先展示秒數this.countdown();this.isShowCount=true;},} </script>

    連續點擊倒計時bug

    此時連續點擊倒計時會有bug,數字越跳越快,主要是重復開啟倒計時造成的。

    其實我們只需要把事件給到 “獲取驗證碼” 所在的span,就可以解決

    <div class="btn checkcode-btn"><span v-show="!isShowCount" @click="getCode">獲取驗證碼</span><span v-show="isShowCount">{{count}} s</span> </div> <script> data () {return {// 是否展示表單的布爾值isShowForm:true,// 拼圖滑塊的文字msg: "向右滑動",// 用戶手機號phoneNum:"",// 最大的計時時間countMax:60,// 倒計時時間,每秒變化的那個數字count:0,// 是否展示秒數所在盒子isShowCount:false} }, ... ... countdown(){// 計時的方法// 倒計時,實際上就是每隔1秒,count減去1let timer = null;this.count = this.countMax;timer = setInterval(()=>{this.count--if(this.count===0){// 清除定時器 clearInterval(timer);}},1000); } </script>

    請求頭和請求攔截器

    接口上有需要我們修改請求頭Content-Type字段,并使用qs.stringnify進行格式轉換:

    需要在請求攔截器加上:

    instance.interceptors.request.use(config=>{if (config.url === "/sendSMS" || config.url === "/wechatUsers/PCLogin") {config.headers["Content-Type"] = "application/x-www-form-urlencoded";}return config },err=>{return Promise.reject(err) })

    安裝qs模塊:

    npm i qs

    api.js中:

    import qs from "qs" // 發送短信驗證碼請求 export const SendSMSAPI = params => request.post("/sendSMS",qs.stringify(params));

    作業

    day01

    聊天對話框

    解題思路:利用v-for遍歷數組,利用v-model獲取變化的值

    //先引入Vue的js文件 <script src="./vue.js"></script>創建Vue對象 new Vue({el:"選擇器",data:{//數據arr:[],val:""//val:"A"(意思是默認值是A)},methods: {//方法}})//獲取變化的值:用v-model 一般是用在父級元素上,獲取子級元素的值的變化 //還可以用在輸入框,獲取輸入框的值v-model = "val"v-model = "text"//遍歷數組---用 v-for"(item, index) in 需要遍歷的數組數組" //誰需要遍歷,就誰用v-for <div v-for='item in arr'><span>{{item.content}}</span></div>//判斷name是A還是B,分別對應給class值,控制類名 //用三元表達式:class="item.name==='A'?'atalk':'btalk'"//三元表達式 表達式?"等于(true)的值":"不等于(false)的值"//點擊事件,點擊給數組添加值,然后再遍歷 @click = '事件名'事件中調用data的值,需要用thismethods:{talkTxt(){this.arr.push(`{name:${this.val},content:${this.text}}`)this.text = ""//點擊之后自動清空文本框}}

    選項卡-tab欄

    思路:事件點擊方法,傳參數,帶參數,然后將參數存起來;利用三元表達式判斷是否等于參數值,給類名值

    @click='add(1)'三元表達式::class='val===1?"current":""'

    todolist-微博新增發言功能

    思路:用數組將內容裝起來,然后遍歷獲取數組的item內容和index索引值,點擊刪除,刪除對應索引值的數組內容。

    用v-for ’(item,index)in arr ‘

    學生管理系統

    思路:用來 v-for = “(item,index)in arr” ;v-show 顯示隱藏(true;false);將索引和item值存儲,然后傳給下個方法;

    JavaScript如何判斷一個值是不是數字?

    第一種方法:isNaN()

    數字返回false 字符串返回true

    缺點:值有一個空串或是一個空格,isNaN將把c當作數字0來處理,所以檢查不嚴謹。

    第二種方法:正則表達式

    /1+.?[0-9]*///判斷字符串是否為數字,判斷正整數用/[1?9]+[0?9]?]?/ //判斷字符串是否為數字 ,判斷正整數用 /^[1-9]+[0-9]*]*////[1?9]+[0?9]?]?/

    reg.test( num )

    第三種方法: 利用typeof的返回值


  • 0-9 ??

  • 總結

    以上是生活随笔為你收集整理的Vue阶段总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。