1. 程式人生 > >學習使用webpack+vue搭建專案

學習使用webpack+vue搭建專案

最近,一直把JS基本語法知識重新鞏固學習的同時,也一直在跟著上篇文章中提到的名為“守候”的博主發表的文章進行學習,今天也將自己在通過他的文章使用webpack+vue搭建專案環境的過程中遇到的值得記錄的點,都一併寫在這裡。
僅僅自己目前對webpack的理解,就是一個打包工具。可以將專案中不同的語言識別轉換成js,從設定的入口檔案找到專案的所有依賴檔案,將專案模組化開發,最終打包為一個或者多個瀏覽器可以識別的JavaScript檔案。更深層次的還沒有進一步理解,不過在操作過程中對其使用有更進一步的理解。
一、基本環境的安裝配置及使用如下:
1. 首先,安裝webpack,建議先全域性安裝後再安裝到本地目錄,具體的原因目前自己沒有深入理解。

npm install -g webpack  //全域性安裝 
npm install --save-dev webpack

2 . 在package.json中,對專案描述資訊及專案所需要使用到的相關依賴進行新增。可以手動建立或通過命令列:npm init。
3.webpack配置檔案的完成:指定入口檔案、出口檔案、載入器及 外掛等。
//基本上就差不多了,需要使用的Vue、element-ui等,按照官方文件說明安裝即可。
4.router.js配置
5.入口檔案和入口檔案模板的配置。
具體的直接參照該博主的系列文章:webpack+vue專案實戰(一,搭建執行環境和相關配置)


6.!!需要注意的點:
(1)由於博主是之前記錄的,webpack、element-ui的版本都和現在有所偏差。可能很多小夥伴都執行報錯,我也是一樣,將版本升級後,再修改對應的配置即可。沒有截圖記錄我當時的報錯原因,反正報錯後,我將所有的東西都升到了最新版,另外在入口檔案中引入element-ui的css樣式時,其預設的檔名已經由theme-default——>改為了theme-chalk。修改完畢後,執行成功。
(2)如下圖所示,突然發現,哎喲~為什麼路由路徑是在dist目錄下呢?而且我們的檔案中並沒有這個路徑。
這裡寫圖片描述

這裡寫圖片描述

這就讓我有點疑惑了,為什麼它的指定路徑會在dist/html下呢?而之前我接觸到的專案都是直接locahost:埠號就可直接運行了,這裡這樣執行卻會報錯。
原因就是我們用了webpack-dev-server構建生成的包,實際是放在記憶體中的,即這裡前面的字首是代表虛擬目錄,因此我們看不到編譯後的dist檔案。查詢webpack-dev-server的定義:

webpack-dev-server是一個小型的node.js Express伺服器,它使用webpack-dev-middleware中介軟體來為通過webpack打包生成的資原始檔提供Web服務。

我想大概比較明朗了,因為我們設定webpack的輸出路徑:

   output: {
      path: path.join(__dirname, 'dist'), /*輸出目錄的配置,模板、樣式、指令碼、圖片等資源的路徑配置都相對於它*/
      publicPath: '/dist/',               
      filename: 'js/[name].js',   
      chunkFilename: 'js/[name].asyncChunk.js?'+new Date().getTime() //chunk生成的配置
    },

而且對npm也進行了設定,可通過簡單的命令執行webpack-dev-server,且設定為熱載入,方便修改後自動重新載入更新效果。
這裡寫圖片描述

上面程式碼中涉及到的:
   __dirname變數值代表程式執行的根目錄;
   path.join:路徑合併   // 特點: 將多個路徑名稱用path.seq串聯起來,然後normalize格式化
   ./                  //當前目錄下
   ../                 //父級目錄
   /                   //根目錄
例如:
   path.join('//foo','bar','//baz/dfj'); // --> '/foo/bar/baz/dfj'       

關於node.js中path物件更多的用法,可參考xiaobing_hope博主的文章”Node.js的Path物件“,裡面有比較詳細的說明喲。

另外,之所以之前我的專案中直接輸入localhost:埠號/#就可以的原因是,之前的專案重新書寫了webpack-dev-server,並沒有直接使用下載的。
這裡寫圖片描述

然後也配置了npm命令的簡單方式:
這裡寫圖片描述

這裡寫圖片描述
上圖表示打包檔案的輸出位置為build資料夾下的根目錄。
簡而言之,如果直接下載安裝,我們線上執行webpack-dev-server時打包的檔案在記憶體中,但我們可以通過自己實現dev-server對其進行改寫後,實現自己想要的效果,如打包檔案放置位置及可編譯及編譯檔案生成的位置……
(3)在瀏覽時,發現博主用click點選事件時,還用到了Vue.js的stop修飾符,這個是用來防止冒泡事件的發生的。冒泡事件簡而言之就是當前事件的傳播性,防止影響到其他事件。
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
注意點的第二條,感覺自己理解亂七八糟的,可能很多地方都存在著錯誤,但還是記錄下來當前的理解,我希望通過自己不斷的學習能回過頭髮現自己的錯誤並改正。小夥伴們看到不對,務必一定指出來,非常感謝!我想,積累是一個從無到有的過程。

二、開發管理系統主頁面
基於第一部分已經搭建好的環境,我也跟隨著博主的腳步去動手實現一個管理系統。因為之前都是直接用的Vue.js的腳手架生成生成,因此預設的專案結構是固定的,如下圖所示。直接輸入localhost:8080會看到vue的圖示介面。
這裡寫圖片描述

現在直接藉助webpack自己寫配置檔案也能實現同樣的效果,動手試試也是很不錯的。而且博主的檔案放置非常清晰,根目錄下就是安裝的依賴資料夾node_modules、原始檔夾src用於存放有效實現程式碼、下面的package.json及webpack.config.babel.js當然就是配置檔案啦。
這裡寫圖片描述
這裡寫圖片描述
js資料夾下的目錄結構如下圖所示:
這裡寫圖片描述
而頁面元件下又將主頁面和其他頁面元件分開放置在不同資料夾中,並且主頁面也將不同的功能實現程式碼都分開放置了,如下圖所示。這樣修改時能很方便的修改某個部分。
這裡寫圖片描述

1.頂部元件欄實現
直接在componets資料夾下新建一個toopbar.vue檔案,簡單的寫一點東西就可以。然後在入口檔案index.js中引入這個檔案並在vue中註冊:

這裡寫圖片描述

最後,在入口模組檔案index.html中直接使用註冊的元件名為標籤使用就可以了。

2.側邊欄的實現
我就直接element-ui中的導航選單配合router實現簡要地實現了該效果。操作同上面頂部元件欄實現一致,不過是在頁面上實現的內容不同而已。注意switch語句中的判斷條件可以為任何型別,但是此處為字串一定呀加上字串,最開始我就沒有加,找了好久的錯誤。。。。

這裡寫圖片描述

好了,主要的實現原理就是這樣子,通過選單項切換到不同的路由介面下,我們仍舊類似的實現方法,只要寫好了,在路由引入后里配置相應的路徑和元件即可。原理就是,當我們輸入主介面的url時,通過router.js中路由匹配到主介面,當點選選單選擇選單項後,又是觸發了路由跳轉到不同的介面,簡單的介面互動就是這樣啦。更具體的實現,不清楚的時候可以去看看該博主的原文,寫的更加的詳細一點,描述也比我有邏輯T T。

三、按需載入

“當打包構建應用時,Javascript包會變得非常大,影響頁面的載入。如果我們能把不同路由對應的元件分割成不同的程式碼塊,然後當路由被訪問時載入對應元件,這樣就更加高效了。”這是Vue.js的官方文件中路由懶載入部分的原文,因此這裡我們也可以將路由下的所有元件都打包在同個非同步塊中,使用命名chunk來提供chunk name(Webpack>2.4),對路由來個“懶載入”

這裡寫圖片描述

四、多個選單項共用同一頁面(根據路由不同,呈現不同的效果內容)
1.首先在router.js裡配置。這裡用到了動態路由匹配,參考資料Vue官方文件:動態路由匹配
2.在選單匹配處傳遞引數:

 selectMenu:function(key, keyPath){
   switch(key){
     case '1':this.$router.push('/index');break;
     case '2-1-1':this.$router.push({name:'待確認訂單',query:{status:'0'}});break;
     case '2-1-3':this.$router.push({path:'/sale/sureList/'/*,name:'訂單管理'*/});break;
   }
 }

3.在介面處利用watch和mounted()監聽路由選擇。
實現過程中遇到的問題,this.$route.push()函式的錯誤使用,具體詳見動態路由匹配不成功。這裡對問題和解決方法都進行了具體的描述,其中命名路由的使用參照了官方文件動態路由部分:

這裡寫圖片描述

檢視 route.push()用法,發現一般有下面的三種用法(不知道為什麼dollar符號不能正確顯示,下面呼叫方法時route前面都有dollar符號的哈),要麼只push路徑path,要麼push name和引數status確定路由。
(1)字串:
router.push(‘home’)
(2)物件:
router.push({path: ‘/login?url=’ + this.$route.path});
(3)命名的路由,後面的引數為動態路由的引數:
router.push({ name: ‘user’, params: { userId: 123 }})
(4)帶查詢引數,變成/backend/order?selected=2
trouter.push({path: ‘/backend/order’, query: {selected: “2”}});

五、購物車統計總價頁面
同樣是跟隨該博主的Vue快速入門的三個小例項動手實踐,另外自己在實現的時候採用element-ui中的el-table,順便加深對其的學習理解。果然,看著很簡單,實現時也是跳進了不少坑。
分析實現:直接在前面實現的基礎上新增加頁面,用來完成購物車計算總價功能。整個流程也是差不多佈局->資料->操作函式實現。

(1)直接先上“html”程式碼:

<template>
  <el-table ref="multipleTable" :data="tableData3" tooltip-effect="dark" style="width: 100%" @selection-change="handleSelectionChange">
    <el-table-column type="selection" width="55">
    </el-table-column>
    <el-table-column label="商品" width="260" prop="product">
      <template slot-scope="scope">
         <img :src="scope.row.product.pro_img" width="98" height="98">
         <div class=‘product-info’>
           <h4>{{scope.row.product.pro_name}}</h4>
           <p>品牌:{{scope.row.product.pro_brand}}</p>
           <p>產地:{{scope.row.product.pro_place}}</p>
           <p>規格/純度:{{scope.row.product.pro_purity}} &nbsp;&nbsp;起定量:{{scope.row.product.pro_min}}</p>
           <p>配送倉儲:{{scope.row.product.pro_depot}}</p>
         </div>
         <div class="clearfix"></div>
      </template>
    </el-table-column>

    <el-table-column  prop="pro_num" label="數量" width="200">
      <template slot-scope="scope">
       <el-input-number v-model="scope.row.pro_num" @change="handleChange" :min="1" :max="10000">
       </el-input-number>
      </template>
    </el-table-column>

    <el-table-column prop="pro_price" label="單價(元)" width="170">
    </el-table-column>
    <el-table-column prop="pro_total" label="金額(元)" width="170">
       <template slot-scope="scope">         
           {{scope.row.pro_num*scope.row.pro_price}}         
      </template>
    </el-table-column>
    <el-table-column label="操作" width="100">
    <template slot-scope="scope">
        <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">刪除</el-button>           </template>
    </el-table-column>
  </el-table>
  <div style="margin-top: 20px">
  </div>
</template>

上面利用el-table自定義列模板,組合其他的元件使用,分別用表格列來代表商品資訊、數量、單價等,表格項中又插入其他的塊,不是直接的資料。使用了scoped slot,這個可以獲取到row,column,$index和store(table內部的狀態管理)的資料,用法參考官方demo及本例。
!!!!!要注意數量列的資料繫結的方法,v-model值和prop的屬性繫結!!!
及後面總金額數量的改變,直接在前面利用{{ scope.row.pro_num*scope.row.pro_price}}呼叫到當前操作的資料項的單價數量。
(2)js部分:

export default{
 data() {
      return {
        tableData3: [{
          product:{
            pro_name: '【斯文】甘油 | 丙三醇',
            pro_brand: 'skc',
            pro_place:'韓國',
            pro_purity: '99.7%',
            pro_min:'215千克',
            pro_depot:'上海倉海倉儲',
            pro_img:''
          },
            pro_price:'800', 
            pro_num:'1',
            pro_total:'800'
        }],
        multipleSelection: []
      }
    },

    methods: {
    //智慧的全選判斷
      toggleSelection(rows) {
        if (rows) {
          rows.forEach(row => {
            this.$refs.multipleTable.toggleRowSelection(row);
          });
        } else {
          this.$refs.multipleTable.clearSelection();
        }
      },
    //當前的選中項及個數,可方便對選中項進行操作,不寫也沒得關係。
      handleSelectionChange(val) {
        this.multipleSelection = val;
        console.log(this.multipleSelection);
      },
    //數量計數器改變值時觸發的函式
      handleChange(){
      }
    }
}

js部分主要是給了table資料,及全選函式及計數函式簡單實現,沒有做複雜的限制。toggleSelection直接是原demo實現,原諒我直接使用了,沒有仔細研究其遞迴原理。最後也實現了博主那樣的效果喲,哈哈。下面圖1是勾選函式的列印結果,圖二是最終的效果。


圖1

這裡寫圖片描述
圖2

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
(3)實現過程中,犯的錯誤和踩得坑也不少。
將總價金額用另一種方式計算,利用計數器改變時觸發的函式:

//下面的value = scope.row
handleChange(value){
  console.log(value);
  console.log(value.pro_num);
  console.log(value);
  value.pro_total = value.pro_num * value.pro_price;
}

結果發現初態:
這裡寫圖片描述
圖3

點選新增按鈕後,計數器變為2,獲取的scope.row物件中num=2,但是!!只要我們通過物件單獨引用pro_num的值時,他的值就變了,始終是變化前一次的值。如下圖4所示:
這裡寫圖片描述
圖4

不知道為什麼會這樣,不過在使用elment-ui其他元件過程中,如多選框,其中的change函式也存在類似的問題,獲取到的始終是改變前的上一輪值,不能實時獲取最新情況。有可耐的小夥伴知道,求告知,感激不盡!

這裡寫圖片描述
圖5

上面圖5是在copy跑博主的小例項選項卡原碼中遇到的問題,繫結屬性時,錯誤的將:放到了引號內,所以一直報錯。不過這種寫法以前也是沒有嘗試過,又學到了一招哈哈。切換選擇不同的項是,當前選中項即啟用狀態顯示同一個顏色,就必然共用同一樣式,不過樣式的顯示這樣顯示可以說是非常機智了,已get。

六、todolist
也就是博主的Vue快速入門的三個小例項中的最後一個例項。實現過程中,依葫蘆化瓢,照著博主的步驟及程式碼,手動敲程式碼,試圖理解透每一點。實現中,沒有使用其他的外掛,頁面均用原生的html標籤實現,也順道溫習。然鵝,我還是遇到了目前還未找出的bug及不理解的css樣式。
1.先簡單記錄下不熟的點:
單選框或者輸入框,均用input,只是據情況設定type,且單選框的選擇事件用click觸發;
鍵盤的輸入狀態觸發:
keyup.13 keyup.enter–>回車鍵
keyup.esc –>返回鍵
dbclick –>雙擊
2.問題及bug:
(1)????關於獲取到當前滑鼠放置位置,刪除按鈕X的顯示????????

li .close{
         position: absolute;
         color: #f00;
         font-size: 20px;
         line-height: 40px;
         height: 40px;
         right: 20px;
         cursor: pointer;
         display: none;
         top: 0;
      }
      li:hover .close{display: block;} //為什麼設定為塊元素時才顯示,否則就看不到X!!
      li .text-keyword{
         height: 40px;
         padding-left: 10px;
         box-sizing: border-box;
         margin-left: 10px;
         width: 80%;
         display: none;
      }  

去掉那句後,檢查元素,還是看不到

這裡寫圖片描述

(2)雙擊事件不起作用!導致不能修改原有的列表資訊。