去哪了網(wǎng)項目總結(jié)(移動端)

一勺届、啟動項目

1. 安裝腳手架和依賴

首先保證你的電腦上有node和npm主到,版本越新越好

  1. npm install -g vue-cli
    全局安裝腳手架工具派桩,安裝的時候可以指定版本
  2. vue init webpack myProject
    用webpack工具初始化vue項目,myProject是項目名稱徘层,可以自己命名
  3. cd myProject
    進入創(chuàng)建的vue項目目錄
  4. npm install
    安裝項目所需要的依賴,也就是安裝一些必要的插件
  5. npm run dev
    開始運行項目

2. 項目代碼介紹

  1. README.md----項目的介紹說明文件
  2. package.json----一些第三方模塊的依賴
  3. package-lock.json----確定第三方包的版本利职,保證團隊編程的統(tǒng)一
  4. LICENSE----開源協(xié)議的說明(就是你的代碼別人可以怎么用趣效,是否可用于商業(yè)化等)
  5. index.html----首頁的模板文件
  6. .postcssrc.js----對postcss的一個配置文件,postcss會處理我們的css
  7. .gitignore----把不想提交到線上的文件放在這里
  8. eslintrc.js----寫代碼的規(guī)范
  9. .editorconfig----配置了一些編輯器的語法猪贪,可以自行添加修改
  10. .babelrc----語法解析器跷敬,把我們寫的vue單文件組件寫法的代碼解析成瀏覽器能夠識別的代碼
  11. static----靜態(tài)資源(靜態(tài)圖片或者我們模擬的json數(shù)據(jù))
  12. node_modules----我們依賴的第三方包
  13. src---我們項目的源代碼
  14. config----我們項目的配置文件

index.js 基礎(chǔ)的配置信息
dev.nav.js 開發(fā)時的配置信息
prod.nev.js 線上的配置信息

  1. build----我們項目打包的一些webpack的配置內(nèi)容

3. 多頁應(yīng)用 vs 單頁應(yīng)用

3.1 多頁應(yīng)用

  • 什么是多頁應(yīng)用?

頁面每次跳轉(zhuǎn)热押,后臺都會返回一個新的HTML頁面

  • 執(zhí)行步驟:

頁面跳轉(zhuǎn)----->返回HTML

  • 優(yōu)缺點:

優(yōu)點:

  1. 首屏?xí)r間快(請求了第一個HTML頁面西傀,就立即展示)
  2. SEO效果好(搜索引擎可以識別HTML中的內(nèi)容,而我們每個頁面都放在HTML中桶癣,搜索效果好)

缺點:
頁面切換慢(每次跳轉(zhuǎn)都要發(fā)一個HTTP請求)

3.2 單頁應(yīng)用

  • 什么是單頁應(yīng)用拥褂?

js感知到url的變化,js會動態(tài)的清除掉當(dāng)前頁面的內(nèi)容饺鹃,把下個頁面的內(nèi)容掛載到當(dāng)前頁面上,頁面始終就有一個,路由是由我們前端做了悔详。

  • 執(zhí)行步驟:

頁面跳轉(zhuǎn)----->js渲染

  • 優(yōu)缺點:

優(yōu)點:
頁面切換快
缺點:
首屏?xí)r間稍慢镊屎,SEO差(現(xiàn)在可以解決)

4. 項目代碼初始化(移動端)

  1. 設(shè)置meta標簽
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
  2. 引入 reset.css---把不同手機的瀏覽器的初始化樣式做一個統(tǒng)一
  3. 引入border.css---解決移動端1像素邊框的問題(因為手機分辨率不同)
  4. 引入fastclick庫---解決某些機型點擊后延遲300ms的問題。

    怎么引入伟端?

    1. npm install fastclick --save(save是指不管開發(fā)和線上都使用)
    2. main.js中引入杯道,import fastClick from "fastclick",然后
      fastClick.attach(document.body)责蝠,綁定到body上
  5. iconfont矢量圖標庫建立一個圖標倉庫

使用方法:

  • 本地引用:
  1. 打開官網(wǎng)->圖標管理->我的項目->新建項目->選擇所需圖標到購物車->添加至新建項目
  2. 將選擇好的圖標倉庫下載到本地
  3. 把所有的字體文件(以svg,eot,ttf,woff等結(jié)尾的文件)和iconfont.css文件拿出來党巾,其他的文件沒用
  4. 把所有的字體文件放在一起iconfont文件夾(本項目將iconfont文件夾放在了assets里面styles文件夾下)
  5. 修改iconfont.css中的字體路徑
  6. main.js中全局引入iconfont.css文件或者在需要字體圖標的文件里局部引入iconfont.css文件
  7. 在官網(wǎng)字體所在倉庫里把iconfont字體的地址粘貼到代碼對應(yīng)位置,OK

優(yōu)點:在沒有網(wǎng)絡(luò)的時候霜医,字體圖標可以正常顯示
缺點:如果想要在倉庫里新加圖標應(yīng)用到項目齿拂,那么必須重新引入

  • 在線引用:
  1. 在字體倉庫下有生成在線鏈接,點擊肴敛,生成在線鏈接署海,放入項目的css文件夾下面,不要忘了字體的樣式也要引入
  2. 在官網(wǎng)字體所在倉庫里把iconfont字體的地址粘貼到代碼對應(yīng)位置,OK

優(yōu)點:添加新的圖標的時候医男,只需要在重新生成一次在線鏈接砸狞,把鏈接放入項目中 就可以使用新添加的圖標啦
缺點:沒網(wǎng)的時候不會顯示,以file協(xié)議打開也不會顯示镀梭。

二刀森、Home頁面

1. Home頁面----Header.vue組件

  1. 安裝stylus工具(寫css)

npm install stylus --save
npm install stylus-loader --save
npm run dev(重新啟動項目)

  1. 代碼優(yōu)化

公用樣式

  1. 把公用樣式放到一個文件里

本項目在assets下styles建了varibles.styl文件,存放公共樣式报账,比如全局背景色$bgColor = ##00bcd4定義在這個文件里

  1. 使用

在要公用樣式的組件里面的style里面引入這個文件@import '../../../assets/styles/varibles.styl'研底,然后background: $bgColor

  1. 優(yōu)點:便于維護和修改

自定義路徑
在項目中,我們都知道src可以用@代替透罢,我們也可以自定義一些路徑
步驟:
build->webpack.base.conf.js找到resolve配置項榜晦,可以自定義

'@': resolve('src'),
'styles': resolve('src/assets/styles'),

現(xiàn)在上面那個引用就可以改成@import '~styles/varibles.styl'
注意:在一個css中引用另一個css文件,如果想使用自定義路徑羽圃,路徑前面必須加上~

~ 是 stylus-loader 到東東乾胶,參考 https://github.com/shama/stylus-loader
~styles 表示相對 styles,然后我們在 webpack 配置了 styles 的 alias朽寞,就能找到了它的路徑了

2. Home頁面----Swiper.vue組件

  1. 建立一個index-swiper分支(在真實的開發(fā)環(huán)境下胚吁,每一個獨立功能都有一個獨立分支)
  • 在githup下建立分支
  • 在終端 git pull---把線上的改變拉到本地
  • git checkout 'index-swiper'---切換分支
  • 新分支開發(fā)完成
  • git add . ; git commit -m ; git push (index-swiper)
  • 將新分支的代碼合并到主分支
  • git checkout master(切換到主分支)
  • git merge index-swiper(將新分支代碼合并到當(dāng)前分支)
  • git push(提交到線上倉庫)
  1. 使用 Vue-Awesome-Swiper輪播插件
    使用方法:參照官網(wǎng)或者 vue-awesome-swiper的使用以及API整理

問題:怎么防止頁面抖動?
描述:網(wǎng)速較慢時愁憔,輪播圖還沒加載出來腕扶,輪播圖所在位置高度為零,下面的元素占據(jù)了輪播圖的位置吨掌,等到輪播圖加載出來半抱,就會把其他元素擠下去脓恕,頁面抖動
注意:輪播圖中圖片也不要給固定長寬,要用百分比
解決辦法:

  1. 在輪播圖外面包裹一層固定寬高的盒子(不推薦)

更換圖片或者改變圖片大小的時候窿侈,頁面可能會發(fā)生錯亂

  1. 在輪播圖外包裹一層長寬比例以圖片一致的盒子
    width: 100%;height: 33%vw

這種方法可以炼幔,但是兼容性不太好

  1. 在外面包裹一個盒子,盒子設(shè)置如下:(這是普遍的用法BFC)
.wrapper
     overflow hidden
     width 100%
     height 0
     padding-bottom 26.67%
     background #eee
  1. 在vue項目組件中使用子組件(外部組件)史简,怎么去修改子組件的樣式乃秀?
  1. 去掉scoped,但會污染全局組件

去掉scoped,style樣式就不再局限與本組件圆兵,變成全局樣式跺讯,自然會影響到子組件的樣式

  1. 混用本地和全局樣式
<style>
/* 全局樣式 */
</style>
<style scoped>
/* 本地樣式 */
</style>
  1. 使用深度作用選擇器
    如果你希望 scoped 樣式中的一個選擇器能夠作用得“更深”,例如影響子組件殉农,你可>以使用 >>> 操作符:
<style scoped>
.a >>> .b {
 /* ... */
}
</style>

有些像 SASS 之類的預(yù)處理器無法正確解析 >>>刀脏。這種情況下你可以用 /deep/操作符取而代之 —— 這是一個 >>> 的別名,同樣可以正常工作超凳。

3. Home頁面----Icons.vue組件

  1. 輪播時分頁

這就需要兩次循環(huán)愈污,第一次循環(huán)把所有的頁找出來,然后在循環(huán)每一頁中的元素

4. Home頁面----Recommend.vue組件

  1. 省略號的使用

有時候一句話太長轮傍,我們又不想讓它換行暂雹,但是又得提醒用戶后面還有內(nèi)容,這就需要省略號啦
怎么添加创夜?

  1. 單行文本的溢出
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;

注意:有的時候在部分機型上沒有效果杭跪,那么就換成多行文本的溢出形式就行,把多行的行數(shù)調(diào)成1行

  1. 多行文本的溢出 (WebKit)
overflow hidden;
 text-overflow: ellipsis;
 display: -webkit-box; /*將對象作為彈性伸縮盒子模型顯示*/
 -webkit-line-clamp: 1; /* 限制在一個塊元素顯示的文本的行數(shù) */
 -webkit-box-orient: vertical; /* 垂直排列 */
 word-break: break-all;  /* 內(nèi)容自動換行 */

適用場景:這個屬性只合適WebKit瀏覽器或移動端(絕大部分是WebKit內(nèi)核的)瀏覽器

  1. 多行文本的溢出 (利用定位和偽類元素)
p{
   position: relative; 
   width:400px;
   line-height: 20px; 
   max-height: 60px;
   overflow: hidden;
}
p::after{
   content: "..."; 
   position: absolute; 
   bottom: 0; 
   right: 0; 
   padding-left: 40px;
   background: -webkit-linear-gradient(left, transparent, #fff 55%);
   background: -o-linear-gradient(right, transparent, #fff 55%);
   background: -moz-linear-gradient(right, transparent, #fff 55%);
   background: linear-gradient(to right, transparent, #fff 55%);
}

適用場景:文字內(nèi)容較多挥下,確定文字內(nèi)容一定會超過容器的揍魂,那么選擇這種方式不錯桨醋。但文字未超出行的情況下也會出現(xiàn)省略號,可結(jié)合js優(yōu)化該方法棚瘟。 效果圖

注:

  • 將height設(shè)置為line-height的整數(shù)倍,防止超出的文字露出喜最。
  • 給p::after添加漸變背景可避免文字只顯示一半偎蘸。
  • 由于ie6-7不顯示content內(nèi)容,所以要添加標簽兼容ie6-7(如:<span>…<span/>)瞬内;兼容ie8需要將::after替換成:after迷雪。

可以結(jié)合js代碼優(yōu)化:

$(function(){
//獲取文本的行高,并獲取文本的高度蜒程,假設(shè)我們規(guī)定的行數(shù)是五行蜂怎,那么對超>>>過行數(shù)的部分進行限制高度劲弦,并加上省略號
  $('p').each(function(i, obj){
       var lineHeight = parseInt($(this).css("line-height"));
       var height = parseInt($(this).height());
       if((height / lineHeight) >3 ){
           $(this).addClass("p-after")
           $(this).css("height","60px");
      }else{
           $(this).removeClass("p-after");
       }
   });
})

5. 使用axios發(fā)送Ajax請求

  1. npm install axios --save; 在Home組件中引入import axios from 'axios'
  2. Home頁面共有5個組件都需要Ajax獲取數(shù)據(jù),如果每個組件都發(fā)一個請求赁严,那么就會降低頁面的性能扰柠。
    解決辦法:可以在Home頁面請求數(shù)據(jù)一次,然后把請求的數(shù)據(jù)通過父子組件傳值(props)傳遞給子組件疼约。Ajax請求數(shù)據(jù)的操作本項目是在mounted鉤子函數(shù)中完成的卤档,其實在created中也可以,相當(dāng)于數(shù)據(jù)初始化程剥。
  3. 本地mock數(shù)據(jù)

注意:

  • 本地mock的數(shù)據(jù)要寫在static目錄下劝枣,因為只有static目錄下的文件才可以被外部訪問到,其他目錄下的文件不能被訪問织鲸,訪問時會自動跳轉(zhuǎn)到首頁的
  • mock文件夾是本地數(shù)據(jù)舔腾,不想提交到線上,那么就在.gitignore中寫入
    static/mock
  • json文件內(nèi)的元素以,分割昙沦,不過最后一個元素不要加,琢唾,容易解析錯誤
  1. 那么我們訪問數(shù)據(jù)時就可以axios.get('/static/mock/index.json')

問題:我們是本地模擬數(shù)據(jù),上線前還要修改路徑盾饮,上線前修改代碼是有風(fēng)險的采桃,不推薦這么做,怎么辦丘损?

解決:
config目錄下index.js文件中的proxyTable中修改配置(這是由webpack-dev-server工具提供的)

proxyTable: {
     '/api':{
       target: 'http://localhost:8080',//訪問的服務(wù)器端口地址普办,默認的,后期如果修改服務(wù)器地址徘钥,直接改這個
       pathRewrite: {//路徑替換
         '^/api': '/static/mock'
       }
     }
   },

三衔蹲、City頁面

1. better-scroll 滾動組件的使用

當(dāng) better-scroll 遇見 Vue

  1. 安裝使用

npm install better-scroll --save安裝
import BScroll from 'better-scroll'在需要滾動的組件中引入

使用
mounted () {
    this.scroll = new BScroll(this.$refs.wrapper)
}
  1. html格式(需要包裹兩層)
<div class="wrapper">
 <div class="content">
   <div>...</div>
   <div>...</div>
     ...(需要滾動的元素)
 </div>
</div>

注意:wrapper(父元素)的高度一定要小于content(子元素)的高度才會滾動,否則無法滾動


image.png

2. offsetTop的理解

注意:

  • offsetTop的參考點是:與當(dāng)前元素相距最近的經(jīng)過定位(position不為static)的父級元素(offsetParent)呈础,并不是我以前認為的body元素
    具體情況如下:
  1. position為fixed時舆驶,offsetParent為null,offsettop的值和top相等而钞。此時元素是以視口來定位的沙廉。
  2. position非fixed,父級元素?zé)o定位(static)時臼节,offsetParent為body撬陵。
  3. position非fixed,父級元素有定位時网缝,offsetParent為最近的有定位的父級元素巨税。
  4. body元素,offsetParent為null粉臊,offsettop為0 草添。

3. 通過函數(shù)節(jié)流可以減少部分操作的執(zhí)行頻率,提高網(wǎng)頁的性能

以下代碼就是通過一個計時器進行節(jié)流扼仲,意思是若你剛開始進行這個操作的時候远寸,會延遲16ms在執(zhí)行促王;若是在16ms之間你有進行手指滾動操作,會把你當(dāng)前執(zhí)行的取消而晒,在開始執(zhí)行新的操作

 if(this.touchStatus){
                //通過添加計時器對函數(shù)進行節(jié)流蝇狼,提高性能
                if(this.timer){
                    clearTimeout(this.timer)
                }
                this.timer = setTimeout(()=>{
                    //const startY = this.$refs['A'][0].offsetTop
                    const touchY = e.touches[0].clientY - 74
                    const index = Math.floor((touchY - this.startY) / 23)
                    if(index >= 0 && index <= this.letters.length){
                        this.bus.$emit('change',this.letters[index])
                    }
                },16)
                
                
            }

4. 移動端touch事件和鼠標事件

移動端的touch click事件的理解+點透
觸屏事件與鼠標事件

說明: 在很多情況下,觸摸事件和鼠標事件會同時觸發(fā)倡怎,目的是讓沒有對觸摸設(shè)備做優(yōu)化的代碼也可以在觸摸設(shè)備上正常運行迅耘。當(dāng)然,如果你使用了觸摸事件监署,那么可以通過e.preventDefault()來阻止鼠標事件被觸發(fā)

1. 事件說明

觸屏事件:

  • touchstart 觸摸開始(手指放在觸摸屏上)
  • touchmove 拖動(手指在觸摸屏上移動)
  • touchend 觸摸結(jié)束(手指從觸摸屏上移開)
  • touchcancel颤专,是在拖動中斷時候觸發(fā)。

鼠標事件:

  • mouseover 鼠標進入
  • mousemove 鼠標移動
  • mousedown 鼠標按下觸發(fā)
  • mouseup 鼠標抬起觸發(fā)
  • click 鼠標點擊事件钠乏,包括mousedown和mouseup2個過程

觸發(fā)規(guī)則:

在觸屏操作后栖秕,手指提起的一剎那(即發(fā)生touchend后),系統(tǒng)會判斷接收到事件的element的內(nèi)容是否被改變:

  • 如果內(nèi)容被改變晓避,會解析為touch事件簇捍,接下來的click事件都不會觸發(fā),
  • 如果內(nèi)容沒有改變俏拱,則會解析為click事件暑塑,按照mousedown,mouseup锅必,click的順序觸發(fā)事件事格。
    特別需要提到的是,在解析為click事件時搞隐,只有再觸發(fā)一個觸屏事件時驹愚,才會觸發(fā)上一個事件的mouseout事件。
    通常click事件官網(wǎng)文檔是說會延時200~300ms,不過項目通過引入fastclick已經(jīng)解決

觸發(fā)順序:

  • 移動端劣纲,點擊一下會觸發(fā):
    touchstart->touchend->mouseover->mousedown-> mouseup->click;
  • 移動端逢捺,滑動,觸發(fā): touchstart->touchmove->touchend;
  • pc端味廊,點擊: mouseover->mousemove->mousedown-> mouseup->click;
  • pc端蒸甜,移動: mouseover->mousemove

執(zhí)行順序代碼演示:

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
      #level0 {
        /* width: 500px;
        height: 500px; */
      }
      #level1-0 {
        background: red;
        width: 500px;
        height: 500px;
      }
      #level1-1 {
        background: green;
        width: 500px;
        height: 500px;
      }
    </style>
  </head>
  <body>
    <div id="level0">
      <div id="level1-0">
      </div>
      <div id="level1-1">
      </div> 
    </div>
  </body>
  <script type="text/javascript">
    var level10 = document.getElementById("level1-0");
    level10.addEventListener('touchstart', function(e) {
      console.log(1);
      e.preventDefault()
    });
    level10.addEventListener('touchmove', function(e) {
      console.log(2);
    });
    level10.addEventListener('touchend', function(e) {
      console.log(3);
    });
    level10.onclick = function() {
      console.log(5);
    }
    document.body.onclick = function() {
      console.log('6');
    }
  </script>
</html>
//

在紅色區(qū)域點擊會出現(xiàn)什么效果呢棠耕? 出現(xiàn)的是 1 3 5 6余佛, 奇怪了 touchmove 為何不執(zhí)行,因為我們并沒有移動窍荧,也就是說辉巡,必須觸碰到屏幕上面,而且發(fā)生了移動動作蕊退,touchmove才執(zhí)行郊楣,現(xiàn)在我們觸碰到憔恳,而且手指稍微動一下,發(fā)現(xiàn)輸出的效果是净蚤, 1 2(+) 3, 其中touchmove 可能觸發(fā)多次钥组,又奇怪了, click為何不執(zhí)行今瀑, 因為 click執(zhí)行的條件是 點擊程梦, 而且不移動 所以一般情況下,我們可以理解成 touchmove和click是相斥的橘荠。
我們知道屿附,當(dāng)一個用戶在點擊屏幕的時候,系統(tǒng)會觸發(fā)touch事件和click事件哥童,touch事件優(yōu)先處理挺份,touch事件經(jīng)過 捕獲,處理, 冒泡 一系列流程處理完成后贮懈, 才回去觸發(fā)click事件

2. 點透事件

  • 點透發(fā)生的條件匀泊,
  • A 和 B不是后代繼承關(guān)系(如果是后代繼承關(guān)系的話,就直接是冒泡子類的話題了)
  • A發(fā)生touch朵你, A touch后立即消失探赫, B事件綁定click
  • A z-index大于B,即A顯示在B浮層之上

點透發(fā)生的理由:

當(dāng)手指觸摸到屏幕的時候撬呢,系統(tǒng)生成兩個事件伦吠,一個是touch 一個是click,touch先執(zhí)行魂拦,touch執(zhí)行完成后毛仪,A從文檔樹上面消失了,而且由于移動端click還有延遲200-300ms的關(guān)系芯勘,當(dāng)系統(tǒng)要觸發(fā)click的時候箱靴,發(fā)現(xiàn)在用戶點擊的位置上面,目前離用戶最近的元素是B荷愕,所以就直接把click事件作用在B元素上面了.

點透消除的方法:

  1. e.preventDefault()取消點擊事件
level10.addEventListener('touchend', function(e) {
   e.preventDefault();
});
  1. touch操作延遲3s后關(guān)閉
setTimeout(() => {
   level10.style.display = 'none';
}, 300);
<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
      #level0 {
        /* width: 500px;
        height: 500px; */
        position: relative;
      }
      #level1-0 {
        position: absolute;
        z-index: 1;
        background: red;
        width: 500px;
        height: 500px;
      }
      #level1-1 {
        background: green;
        width: 500px;
        height: 500px;
      }
    </style>
  </head>
  <body>
    <div id="level0">
      <div id="level1-0">
      </div>
      <div id="level1-1">
      </div> 
    </div>
  </body>
  <script type="text/javascript">
    var level10 = document.getElementById("level1-0");
    var level11 = document.getElementById("level1-1");
    level10.addEventListener('touchstart', function(e) {
      level10.style.display = 'none';
      e.preventDefault()
    });
    level11.onclick = function() {
      console.log('level11莫名被點擊了');
    }
  </script>
</html>

5. vue中eventbus使用的那些坑

參考:vue中使用eventbus踩過的坑
Vue的鉤子函數(shù)
聲明:在已經(jīng)用到vue-router并且跨頁面(跨路由)傳值的情景衡怀,最好用vuex,不要用eventbus,因為在頁面跳轉(zhuǎn)時,新頁面組件的加載和舊頁面組件的銷毀順序不好把握安疗。
本項目我就是Home頁面和City頁面使用的bus總線的方式傳值抛杨,出現(xiàn)的問題和解決方案:
最初代碼:

這些代碼在同一個頁面沒有路由跳轉(zhuǎn)的組件間傳值是沒有問題的,但是荐类,不同頁面間傳值就有問題啦

//City頁面
methods: {
    handleClickChange (city) {
        this.bus.$emit('cityChange',city)
        localStorage.city = city
        this.currentCity = city
    }
}
//Home頁面
methods: {
        handleCity (city) {
        this.city = city
        console.log(city)
        localStorage.city = city
    }
},
mounted () {
    this.bus.$on('cityChange',this.handleCity)
},

問題:

  1. 問什么第一次觸發(fā)Home頁面的on事件沒有執(zhí)行怖现?
  2. 后面再次觸發(fā)時Home頁面的on事件就開始執(zhí)行,并且on事件的執(zhí)行次數(shù)一次次的增加,就像沒有撤銷一樣屈嗤?

問題一解決:

因為vue-router切換時潘拨,先加載新組件,但是在新組件渲染完成還沒有掛載前饶号,銷毀舊組件铁追,在掛載新組件

切換時順序:
新組件: beforeCreate
新組件: created
新組件: beforeMount
舊組件: beforeDestroy
舊組件: destroy
新組件: mounted
解決方案:
在City頁面(舊組件)的$emit事件寫在beforeDestroy,destroy這兩個生命周期鉤子函數(shù)中,Home頁面(新組件)的$on事件寫在beforeCreate,created,beforeMount中茫船,才能夠正確傳值

改正后代碼:

//City頁面
destroyed () {
    this.bus.$emit('cityChange',this.currentCity)
}
//Home頁面
methods: {
    handleCity (city) {
        this.city = city
        console.log(city)
        localStorage.city = city
    }
},
created () {
    this.bus.$on('cityChange',this.handleCity)
},

問題二解決:
兩個頁面都要寫上

beforeDestroy () {
    bus.$off('get', this.handleCity)
},

就是說脂信,這個$on事件是不會自動清楚銷毀的,需要我們手動來銷毀

6. vuex的引入和使用

  1. 引入:
  • npm install vuex --save 安裝
  • src->store->index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
   state: {
      city: '北京'
   },
   actions: {
      cityChange (ctx,city) {
           // console.log(city)
           ctx.commit('change',city)
       }
   },
   mutations: {
       change (state,city) {
           state.city = city
       }
   }
})
``
  • import store from './store'main.js中引入透硝,然后注冊到實例對象中
  1. vuex中mapState的使用

mapState的作用就是把vuex的state里面的數(shù)據(jù)映射到組件中狰闪,可以讓組件直接使用,不用再去store中調(diào)用濒生,減少代碼的復(fù)雜度
本項目的使用:

<script>
import { mapState } from 'vuex'
export default {
    computed: {
        ...mapState(['city']) //把state中的city屬性值映射到該組件計算屬性的city上
    }
}
</script>

所以埋泵,現(xiàn)在代碼中this.$store.state.city === this.city

  1. vuex中mapMutations的使用
import { mapState, mapMutations } from 'vuex'
methods: {
    handleCityChange (city) {
        // this.$store.commit('cityChange',city)
        this.cityChange(city)
        this.$router.push('/')
    },
    ...mapMutations(['cityChange'])//把mutations中的cityChange方法映射到該組件cityChange方法上
},

7. localStorage的使用

本項目使用vuex之后可以改變狀態(tài),但是刷新之后數(shù)據(jù)又變成初始值罪治,怎樣才能讓數(shù)據(jù)保持改變后的狀態(tài)呢丽声?
使用localStorage,將傳過來的值用localStorage本地緩存起來觉义,與cookie的效果有點像雁社,但cookie是服務(wù)器端的
把上面的代碼這樣寫,就能夠保留狀態(tài)

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

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        city: localStorage.city || '北京'
    },
    mutations: {
        cityChange (state,city) {
            state.city = city
            localStorage.city= city
        }
    }
})

注意:有些瀏覽器因為用戶關(guān)閉了本地存儲或使用了隱身模式晒骇,使用localStorage瀏覽器可能會拋出異常霉撵,解決辦法如下:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let defaultCity = '北京'
try {
    if(localStorage.city){
        defaultCity = localStorage.city
    }
}catch (e) {}
export default new Vuex.Store({
    state: {
        city: defaultCity
    },
    mutations: {
        cityChange (state,city) {
            state.city = city
            try{
                localStorage.city = city
            }catch (e) {} 
        }
    }
})

就是把所有的localStorage.city都放在try catch
但是try catch是什么東西?
try catch是一種錯誤處理機制洪囤,try...catch語句將能引發(fā)錯誤的代碼放在try塊中徒坡,并且對應(yīng)一個響應(yīng),然后有異常被拋出
try語句允許我們定義在執(zhí)行時進行錯誤測試的代碼塊瘤缩。
catch 語句允許我們定義當(dāng) try 代碼塊發(fā)生錯誤時喇完,所執(zhí)行的代碼塊。
finally 語句在 try 和 catch 之后無論有無異常都會執(zhí)行剥啤。
注意: catch 和 finally 語句都是可選的锦溪,但你在使用 try 語句時必須至少使用一個。

8. keep-alive的使用

頁面不使用keep-alive府怯,頁面每次跳轉(zhuǎn)都要重新加載一次頁面刻诊,非常影響性能
如下圖所示:


解決辦法:在頁面顯示位置外面包裹一層keep-alive
如下:

<keep-alive>
  <router-view/>
</keep-alive>

效果如下圖:
頁面只加載了一次,通過keep-alive富腊,把頁面保存到內(nèi)存里面坏逢,再次加載只需要去內(nèi)存里面去取就行

laalllll.gif

問題:如果說城市不變域帐,頁面確實不必再次加載赘被,但是如果城市改變了是整,頁面內(nèi)容不變就出問題啦,怎么解決呢民假?
keep-alive提供了一個生命周期鉤子函數(shù)activated,將這個鉤子寫在頁面里浮入,只要這個頁面顯示,不管是不是從內(nèi)存中取得羊异,它都會執(zhí)行事秀,所以我們可以在這個鉤子里進行當(dāng)前城市與上一個城市進行對比,若城市不同野舶,就發(fā)一個Ajax請求
代碼如下:

methods: {
      getHomeInfo(){
        axios.get('/api/index.json?city=' +this.city )//請求數(shù)據(jù)時帶上城市信息參數(shù)
        .then(this.getHomeInfoSucc)
      },
      getHomeInfoSucc(res){
        console.log(res)
        res = res.data
        if(res.ret && res.data){
          this.swiperList = res.data.swiperList
          this.iconList = res.data.iconList
          this.recommendList = res.data.recommendList
          this.weekendList = res.data.weekendList
        }
      }
    },
    mounted () {
        this.lastCity = this.city//將最初的城市信息保存下來
        this.getHomeInfo()
    },
    activated () {
        if(this.lastCity !== this.city){
            this.lastCity = this.city//為上一個城市重新賦值
            this.getHomeInfo()
        }
    }

四易迹、Detail頁面

1. Detail頁面---banner組件

1.1 <router-link>問題

router-link在頁面中會被渲染成a標簽,所以會改變router-link內(nèi)包裹內(nèi)容的顏色平道,怎么解決睹欲?

  1. 直接給router-link包裹的內(nèi)容重新定義顏色,不要在使用繼承來的顏色
  2. 直接用router-link替換掉內(nèi)部包裹的標簽一屋,用tag指向原來的標簽
        <ul>
            <router-link to="/detail">
                <li>
                      點我
                </li>
            </router-link>  
        </ul>

        <ul>
            <router-link to="/detail" tag='li'>                
                      點我
            </router-link>  
        </ul>

1.2 動態(tài)路由的使用

配置路由時:

   {
      path: '/detail/:id',
      name: 'detail',
      component: Detail
    }

頁面中要把信息傳過來

<ul>
    <router-link 
    :to='"/detail" + item.id'
    tag='li'>                
              點我
    </router-link>  
</ul>

2. Detail頁面---公用Gallery組件

  • 如果一個組件會被多個頁面或組件引用窘疮,就應(yīng)該設(shè)為公用組件,放在一起
    本項目在src目錄下設(shè)了common目錄存放公用組件冀墨,而且在buildwebpack.base.conj.jsresolve里面修改了common的引用路徑,以后可以直接引用common
    'common': resolve('src/common'),
  • 圖片畫廊公用組件其實就是一組圖片的拖動輪播組件闸衫,所以要使用vue-awesome-swiper插件來實現(xiàn),而該插件又是基于Swiper3的诽嘉,所以插件的一些配置項可以在Swiper3中找答案
  • 一個注意點:如果要修改輪播圖的樣式或者位置蔚出,最好在外層在包裹一層div,不要直接對組件直接進行修改虫腋,要不很容易出現(xiàn)一些莫名其妙的錯誤

3. Detail頁面---Header組件

對全局事件的解綁:
本組件監(jiān)聽了一個全局滾動事件身冬,在任何一個頁面或組件滾動都會觸發(fā)本操作,這明顯是不利的岔乔,我們要的是只在本頁面滾動觸發(fā)本操作而已

methods: {
        handleScroll () {
            console.log('scroll')
            const top = document.documentElement.scrollTop
            if(top >= 45){
                this.headerShow = true
                const opacity = top / 120
                this.styleOpacity = {opacity: opacity}
            }else{
                this.headerShow = false
            }
        }
    },
    activated () {
        window.addEventListener('scroll',this.handleScroll)
    },

1234.gif

所以我們要進行解綁:
利用keep-alive提供的另一個生命周期鉤子deactivated,就是頁面消失的時候該函數(shù)執(zhí)行

deactivated () {
        window.removeEventListener('scroll',this.handleScroll)
 }

4. Detail頁面---List組件

遞歸組件的使用:我們經(jīng)乘煮荩看到的列表分為一級,二級等幾個級別的列表雏门,這就是遞歸組件做出來的嘿歌。

組件的名字(name)用處:

在遞歸組件中,遞歸組件要引用自己的時候茁影,組件的名字就是代表的這個組件宙帝,直接用名字就可以啦

list: [{
          title: '成人票',
          children: [{
              title: '成人三館聯(lián)票',
              children: [{
                  title: '成人三館聯(lián)票 - 清明上河園'
              }]
          },{
              title: '成人五館聯(lián)票'
          },]
      },]
<div  v-for="(item,index) of list" :key="index">
    <div class="list-item">
        <span class="mp-ticketype-ticket"></span>
        {{item.title}}
    </div>
    <div v-if="item.children" class="item-children">
        <detail-list :list="item.children"></detail-list>//遞歸組件使用自己,這是組件名字的用處
    </div>
</div>

5. Detail頁面---ajax請求

  1. 請求時傳參
    拼接的形式募闲,如果參數(shù)比較多步脓,就不適用啦
axios.get('/api/index.json?city=' +this.city )

第二種:

 axios.get('/api/detail.json',{
           params: {
           id: this.$route.params.id
      }
 })
  1. keep-alive可以本地緩存,如果我們不想要一個頁面或組件使用緩存,那么可以:
<keep-alive exclude="Detail">
   <router-view/>
</keep-alive>

現(xiàn)在name=Detail的這個組件就不再使用緩存啦

注意:因為這個頁面不使用緩存啦靴患,相當(dāng)與keep-alive沒有作用啦仍侥,那么它提供的兩個鉤子activated,deactivated就沒有作用啦,因為不使用緩存鸳君,頁面每次都要重新加載农渊,那么mounted,unmounted這兩個鉤子開始每次執(zhí)行都要加載,可以代替上面的兩個鉤子

  1. 組件中的name有什么用
  1. 使用遞歸組件的時候可以通過名字對組件自身進行引用
  2. 對某個頁面取消緩存的時候也要用到name
  3. chrome瀏覽器中的vue 插件中的dom結(jié)構(gòu)列表也要用到name
    image.png
  1. 拖動行為是相互影響的

比如第一個頁面你滾動到底部或颊,那么進入第二個頁面你會發(fā)現(xiàn)砸紊,頁面頁面滾動位置與第一個頁面位置同步,我們想要進入一個新頁面囱挑,頁面位置在頂端醉顽,該怎么辦?

vue-router中的滾動行為中有一個scrollBehavior平挑,在路由routes下面加上這段代碼就可以解決問題徽鼎,使頁面切換的時候始終回到最頂部

scrollBehavior (to, from, savedPosition) {
      if (savedPosition) {
        return savedPosition
      } else {
        return { x: 0, y: 0 }
      }
    }

5. Detail頁面---在banner中加入FadeAnimation.vue動畫組件

新建一個公用的FadeAnimation.vue動畫組件

<template>
    <transition>
        <slot></slot>
    </transition>
</template>
<script>
export default {
    name: 'FadeAnimation'
}
</script>
<style lang="stylus" scoped>
    .v-enter, .v-leave-to {
        opacity: 0
    }
    .v-enter-active, .v-leave-active {
        transition opacity 1s
    }
</style>

使用:

<fade-animation>
      <CommonGallary 
      :imgs = 'this.detailData.gallaryImgs' 
       v-show="showGallary"
       @close="close"
       ></CommonGallary>
</fade-animation>
<script>
import FadeAnimation from 'common/fade/FadeAnimation'
export default {
    name: 'DetailBanner',
    components: {
        FadeAnimation
    },
}
</script>

五、項目的聯(lián)調(diào)弹惦、測試否淤、與發(fā)布上線

1. 項目的聯(lián)調(diào)

本次服務(wù)器是使用的小型本地PHP服務(wù)器

  1. 根據(jù)網(wǎng)上地址安裝XMAPP,https://www.apachefriends.org/zh_cn/download.html
  2. XMAPP默認的項目地址是放在 C:\xampp\htdocs 下棠隐,里面默認有很多個文件(可以都刪除掉)石抡,創(chuàng)建一個api文件夾,里面放\static\mock里的3個json文件(老師并沒有在視頻里演示創(chuàng)建這個文件夾)助泽。
  3. 瀏覽器訪問http://localhost/api/index.json 如果有json數(shù)據(jù)啰扛,就表示服務(wù)器搭建成功了。
  4. 按照視頻里的操作修改\config\index.js 文件嗡贺,修改代理接口
  5. 運行npm run dev隐解,然后訪問http://localhost:8080,數(shù)據(jù)就能正常訪問了诫睬。
proxyTable: {
      '/api':{
        target: 'http://localhost:8080',
        pathRewrite: {
          '^/api': '/static/mock'
        }
      }
    },
//修改后
proxyTable: {
      '/api':{
        target: 'http://localhost:80',//這是本地服務(wù)器地址(:80可以省略煞茫,因為默認端口就是80)
//
    },

本項目是前臺后臺數(shù)據(jù)都在本地的一個項目,較為簡單摄凡,服務(wù)器地址常見的內(nèi)網(wǎng)IP续徽,外網(wǎng)域名都可以

2. 項目的真機測試

  1. 獲取本機的IP地址,在終端中輸入
    ipconfig(windows); ifconfig(ios)
  2. 通過ip地址啟動項目亲澡,但是你會發(fā)現(xiàn)啟動不了钦扭,因為vue項目是通過webpack dev server啟動項目的,而webpack dev server默認不支持IP地址訪問
  3. 修改package.jsondev配置項床绪,就可以用IP地址來訪問啦
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
//修改后
"dev": "webpack-dev-server --host 0.0.0.0 --inline --progress --config build/webpack.dev.conf.js",
  1. 讓手機和電腦在同一個局域網(wǎng)下(連的是同一個WiFi)客情,手機就可以通過IP地址訪問這個項目
  2. 手機上的bug1(手機拖動右側(cè)的字母表的時候其弊,整個屏幕跟著滑動)
    image.png

    解決:添加事件修飾符prevent,阻止該事件的默認行為
    @touchstart.prevent = 'handleTouchStart'
  3. 手機上的bug2
    一些低版本的安卓機會出現(xiàn)白屏的問題
    原因一:手機不支持promise等一些ES6的語法

解決: 安裝一個包膀斋,這個包會自動判斷手機是否支持ES6的新特性梭伐,如不支持,會自動下載
npm install babel-polyfill --save
import 'babel-polyfill'(在main.js中引入)

原因二:webpack-dev-server的問題概页,打包上線后就會解決

3. 項目的打包上線

  1. npm run build生成一個dist目錄籽御,這個目錄的內(nèi)容是我們代碼的一個封裝和壓縮练慕,是我們要上線的內(nèi)容
  2. 把這個包交給后端惰匙,放到后端服務(wù)器的根路徑下
  3. 就可以直接訪問后端服務(wù)器的地址訪問網(wǎng)站啦 http://192.168.43.229/#/
  4. 如果說我們不想把打包的代碼直接扔到服務(wù)器的根目錄下,想放在根目錄的一個project目錄下铃将,該怎么做呢
  • 首先项鬼,修改config/index.js下的build配置項里的打包路徑,把'/'->'/project'
  • 再次打包劲阎,運行npm run build
  • 可以把打包生成的dist目錄下的內(nèi)容放入服務(wù)器根目錄下的project目錄
  • 訪問http://192.168.43.229/project/#/

4. 異步組件實現(xiàn)按需加載

  1. 首先看一下打包生成的dist目錄


    image.png

    以map結(jié)尾的文件绘盟,是開始的時候調(diào)試的時候使用,意義并不是特別大
    css文件悯仙,所有頁面用到的css文件全部打包到這里
    manifest.js:webpack打包生成的所有配置文件
    vendor.js:各個頁面龄毡,組件公用的代碼
    app.js:各個頁面的業(yè)務(wù)邏輯代碼

  2. 我們?yōu)槭裁匆褂卯惒浇M件?


    image.png

    三個js文件锡垄,前兩個幾乎沒法修改
    每次加載頁面沦零,就要把所有的業(yè)務(wù)邏輯代碼加載一下,若是項目比較大货岭,勢必會大大影響頁面的初始加載速度路操,若是app.js小于1mb以下,就沒有必要使用異步組件啦

  3. 異步組件不僅可以在路由中使用千贯,在頁面組件中中只要引入組件的地方都可以使用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屯仗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子搔谴,更是在濱河造成了極大的恐慌魁袜,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敦第,死亡現(xiàn)場離奇詭異慌核,居然都是意外死亡,警方通過查閱死者的電腦和手機申尼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門垮卓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人师幕,你說我怎么就攤上這事粟按∥芴玻” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵灭将,是天一觀的道長疼鸟。 經(jīng)常有香客問我,道長庙曙,這世上最難降的妖魔是什么空镜? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮捌朴,結(jié)果婚禮上吴攒,老公的妹妹穿的比我還像新娘。我一直安慰自己砂蔽,他們只是感情好洼怔,可當(dāng)我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著左驾,像睡著了一般镣隶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诡右,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天安岂,我揣著相機與錄音,去河邊找鬼帆吻。 笑死域那,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的桅锄。 我是一名探鬼主播琉雳,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼友瘤!你這毒婦竟也來了翠肘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤辫秧,失蹤者是張志新(化名)和其女友劉穎束倍,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盟戏,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡绪妹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了柿究。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邮旷。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蝇摸,靈堂內(nèi)的尸體忽然破棺而出婶肩,到底是詐尸還是另有隱情办陷,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布律歼,位于F島的核電站民镜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏险毁。R本人自食惡果不足惜制圈,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望畔况。 院中可真熱鬧鲸鹦,春花似錦、人聲如沸问窃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽域庇。三九已至,卻和暖如春覆积,著一層夾襖步出監(jiān)牢的瞬間听皿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工宽档, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尉姨,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓吗冤,卻偏偏與公主長得像又厉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子椎瘟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容

  • vue概述 在官方文檔中覆致,有一句話對Vue的定位說的很明確:Vue.js 的核心是一個允許采用簡潔的模板語法來聲明...
    li4065閱讀 7,213評論 0 25
  • 基于Vue的一些資料 內(nèi)容 UI組件 開發(fā)框架 實用庫 服務(wù)端 輔助工具 應(yīng)用實例 Demo示例 element★...
    嘗了又嘗閱讀 1,150評論 0 1
  • 33、JS中的本地存儲 把一些信息存儲在當(dāng)前瀏覽器指定域下的某一個地方(存儲到物理硬盤中)1肺蔚、不能跨瀏覽器傳輸:在...
    萌妹撒閱讀 2,082評論 0 2
  • 元代景德鎮(zhèn)瓶、罐之類器型仇冯,采用分段制胎之宿,然后再用胎泥粘合而成,粘接處器表往往突起苛坚,給人以不平之感比被,外壁接痕經(jīng)打磨...
    骨玩閱讀 234評論 0 0
  • 晚上睡前跟女兒說我小時候爬山的故事坪创,小家伙非常感興趣,時不時插上兩句:“如果我看到那種陡的地方我會嗖直接滑下來或者...
    幸福_娟閱讀 221評論 2 2