電商項目(附加github 學習項目)

簡單電商項目代碼地址:https://github.com/Betty09Zhang/shoppingMall

效果瀏覽:www.bettyzm.clude:4000/index.html   登錄名:zm 密碼:123

1. slot 插槽(父子組件通信)

全局模態框組件實現:

在modal.vue 中添加槽

<slot name="tip"></slot>

父傳子

在父組件中直接添加組件

 <modal v-bind:class="{'md-show':isShow}" v-on:close="closeModal">
          <p slot="tips">請先登錄!</p>
          <div slot="closeDialog" @click="isShow=false">關閉</div>
 </modal>

在子組件中引入isShow 變量  props["isShow"]

子傳父

通過觸發在父組件定義的事件   如close =====> 執行父組件中定義的closeModal 方法。

methods:{

           closeModal(){
              this.isShow=false;
            },

在子組件中,通過this.$emit('close') 觸發

 

 

emit/on  事件發佈 和訂閱 

 

2.測試技巧

 模擬mock 數據,json 文件驗證,不用後臺數據。

3. 主頁面開發

頭部:mint-ui headbar

底部:m-ui tarbar  www.dcloud.io/hellomui   (可更換ICON 圖標)

移動端 雙飛翼  搜索框佈局

input 搜索框 display:inline-block  轉換爲行內塊才能一行顯示。

3.1 商品列表開發

加載商品圖片時, <a href="#"><img    v-bind:src=" ‘/static/1.img‘’"  alt=""></a>  圖片需要動態賦值,否則渲染DOM樹是,圖像來不及加載。動態加載時,一開始無SRC屬性,就不會造成圖像路徑找不到的錯誤,使用命令後,需要用單引號將其引入,因爲使用命令後,就要使用js 語句,不再是字符串,要使用字符串時必須用單引號引入。

客戶端發出請求,可用axios插件。

axios

基於promise用於瀏覽器和node.js的http客戶端

特點

  • 支持瀏覽器和node.js
  • 支持promise
  • 能攔截請求和響應
  • 能轉換請求和響應數據
  • 能取消請求
  • 自動轉換JSON數據
  • 瀏覽器端支持防止CSRF(跨站請求僞造)

axois npm 安裝後,導入模塊以後,需要將其掛載爲vue 的原型對象才能使用

Vue.prototype.$axios=axios

若爲跨域請求,需要在服務器端的入口函數中  設置服務器的response Header 

//設置響應頭response header

var app=express()
app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    next();
});

在 利用axios跨域接收 服務器響應的cookie 時,這是不能設置響應頭   res.header("Access-Control-Allow-Origin", "*");必須指定具體前端頁面的域名和端口。在響應頭裏面加上MIME TYPE 的類型。

eg:  res.header("Access-Control-Allow-Origin", "http://127.0.0.1:8080");

       res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
       res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");

        res.header("Content-Type", "application/json;charset=utf-8");

 

開發時,webpack -dev -server 默認是以本地地址 http://localhost/8080 打開前端頁面,要指定具體的域來打開,不要用localhost,否則 服務器響應的cookie 不會由axios跨域訪問寫到客戶端 

 

設置cookie 利用express封裝的方法 response.cookie("userId",value);   獲取cookie       request.headers.cookie。

在使用axio 請求時,在then 的內部不能使用vue 的實例化this ,因爲在內部沒有被綁定。

解決方案:用es6 箭頭函數,箭頭函數可以和父方法共享變量。

export default {
    data(){
        return {
            newsList:[]
        }
    },
    created(){
      this.$ajax.get('/news/').then(function(response){
        
            this.newsList=response.data.list;=======>//  注意response.data 纔可以接收到響應數據。
            console.log(this.newsList);
        }).catch(function(error){
            console.log(error)
            })
    }
}

axios get傳參請求,添加params 字段,傳遞參數;

 var param={pageSize:this.pageSize,pageIndex:this.pageIndex,sort:this.sortFlag?1:-1};
 this.$ajax.get('/goods',{'params':param}).then((response)=>{...

Vue實例中有$route 和$router 屬性,可通過控制檯輸出this 查看。

在Vue2.0 this.$route.query ,this.$route.params 接收router-link 傳的參數。

$route 爲當前router 跳轉對象裏面可以獲取得name,path,query,params 等。

$router 爲 VueRouter 實例,想要導航到不同url,可使用$router.push(‘要跳轉的路徑名’) 的方法。

服務端問題:

服務端express 路由get 方法傳參,url中 需用佔位符

var router=express.Router();

router.get('/newsDetails/:id',function(req,resp,next){
    // resp.send('獲取服務端信息  goods');
    // 接收到請求後,利用模型取數據庫裏面查找  有findAPI  
    var id=req.params.id;
    console.log("id:"+id);....

}

vue-inifinite-scroll   分頁插件  鼠標滾動之後調用的方法  鼠標滾輪距離底部多遠時開始加載滾動接口

<div v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="10"></div>

注意:初始值  應設置busy 爲 false。busy=true 表示禁止加載顯示。

 

4.數據格式問題

get 請求

url 傳值 通過request 獲取

http://localhost:4000/goods?pageSize=3&pageIndex=2&sort=1    ==》express 框架取參數: request.query("pageSize");

http://localhost:4000/goods/3   ==》express 框架取參數: request.params("pageSize");

原生nodejs 是通過     request.url

router.get('/',function(req,resp,next){
    // resp.send('獲取服務端信息  goods');
    // 接收到請求後,利用模型取數據庫裏面查找  有findAPI  


    var pageIndex=req.query('pageIndex');
    console.log(pageIndex);
    var  pageSize=parseInt(req.param('pageSize'));
    var param={};

    var nums=pageSize*(pageIndex-1);

    var sort=req.param('sort');

    var goodsModel=Goods.find(param).skip(nums).limit(pageSize);
    goodsModel.sort({'salePrice':sort});
    goodsModel.exec(function(err,doc){
            if(err){
                resp.json({
                    status: '0',
                    msg: err
                })
            }
            else{
                resp.json({
                    status:'1',
                    msg: '',
                    count: doc.length,
                    list:doc
                })
            }
    })
})

post 請求

通過request.body.屬性  來獲取參數。

注意:在瀏覽器端定義完數據模型model 後記得導出 module.exports=mongoose.model('Users',userSchema);

日期時間轉換  : 定義爲Date 日期型格式數據從數據庫取出數據時格式爲 2015-04-23T00:00:00.000Z,可用moment 日期轉換時間插件來轉化。在main.js 中定義一個過濾器即可。

response.json({})  // 輸出json 格式數據

   response.end()     // 輸出字符串格式數據

    router.get('/',function(req,res,next){

})

var app=express()

app.use(router) =========> 設置完路由之後 ,記得掛載路由。

5.img 動態加載路徑問題

跑起來發現圖片不顯示,錯誤碼爲404, 
 原因:在webpack中會將圖片圖片來當做模塊來用,因爲是動態加載的,所以url-loader將無法解析圖片地址,然後npm run dev 或者npm run build之後導致路徑沒有被加工【被webpack解析到的路徑都會被解析爲/static/img/[filename].png,完整地址爲localhost:8080/static/img/[filename].png】 

利用static目錄 ,而不是把圖片放到別的地方,比如你自己新建一個img文件夾,在動態引用是無效的

js動態生成的路徑無法被url-loader解析到,如果你去build,會發現圖片甚至不會打包輸出到dist目錄(webpack是按需打包的)。

 解決辦法:①將圖片作爲模塊加載進去,比如images:[{src:require(‘./1.png’)},{src:require(‘./2.png’)}]這樣webpack就能將其解析。②將圖片放到static目錄下,但必須寫成絕對路徑如images:[{src:”/static/1.png”},{src:”/static/2.png”}]這樣圖片也會顯示出來,任何放在static/中文件需要以絕對路徑的形式引用:/static[filename]

   <a href="#"><img :src=" '/static/'+item.productImage" alt=""></a>

 

5.router-link 點擊設置

設置 鏈接激活時使用的 CSS 類名。默認值可以通過路由的構造選項 linkActiveClass 來全局配置。

6.引入自己的樣式路徑問題

./: 當前目錄下;         ./component  表示當前目錄同級component文件目錄      
../: 父級目錄;

定義一個css 文件,在main.js 中引入(import 即可)

7.登錄攔截

採用express 中間件

app.use(function(req,resp,next){
    console.log("req.originalUrl: "+req.originalUrl);
    console.log("req.path: "+req.path);
    console.log("cookie:"+req.headers.cookie);

    if(req.headers.cookie){
        console.log('已登錄');
        next();
    }
    else{
        //白名單
        if(req.originalUrl=='/users/logout' || req.originalUrl=='/users/login' || req.originalUrl=='/news/newsList'  || (req.originalUrl.indexOf('/goods/list')>-1)){
            console.log('白名單  通過!');
            next();
        }
        else{
            console.log('請先登錄!');
            resp.json({                     ====> 傳數據到前端===>  前端根據狀態碼 彈框提示
                status:'0',
                msg:'請登錄',
                result:''
            });

            
        }
    }
})

enter 登錄 

在密碼輸入框 中註冊 回車鍵的keyup 時間 @keyup.enter

 

update 更新mongoose

Users.update({'userId':userId,'cartList.productId':productId},{'cartList.$.productNum':productNum,'cartList.$.checked':checked},function(err,doc){
             if(err){
                 resp.json({
                    status: '0',
                    msg: err.message
                })
             }
             else{
                 

                resp.json({
                    status:'1',
                    msg:'',
                    result:'success'
                    });
                     
                 
             }
             
         })

8 利用computed 屬性實時監控變量,得到另一變量的值

  1.監控商品選中框狀態,是否選中全選按鈕。

  2. 監控商品數量按鈕,實時改變價格。

在computed 屬性中定義變量: 例子:

 

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 計算屬性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 實例
      return this.message.split('').reverse().join('')
    }
  }
})

  computed:{

          allSelectedFlag(){
           return this.countSelect==this.cartList.length;
        },
        countSelect(){
           var count=0;

            for(var i=0;i<this.cartList.length;i++){
              if(this.cartList[i].check=='1'){
                ++count;
              }
            }
          return count;
        },

        countSum(){
            var sum=0;
            this.cartList.forEach(function(item){
                sum+=item.productNum*item.salePrice;
            })
            return sum;
          }
      },

8. 定義過濾器   對時間、數字等進行過濾處理,保留兩位小數等。

 8.1 局部過濾器。

import 導入

  在 export default{} 中 定義過濾器 filters: {

       過濾器名稱:導入模塊名

}

import {currency} from '.././util/currency.js'
    export default{
        data(){
            return{
                cartList:[],
                isShow:false,
                productId:'',
               
            }
        },
        mounted(){
          this.getCart();
        },

        filters:{
            currency: currency
        },

 8.2  全局過濾器

import 導入   Vue.filter(過濾器名稱,導入模塊名);

|  過濾器名稱  使用

 <div class="item-total">
                Item total: <span class="total-price">{{countSum | currency('$')}}</span>
 </div>
 


import './util/currency.js'
 //掛載
 Vue.prototype.$ajax=Axios;

 Axios.defaults.baseURL='http://127.0.0.1:4000';
 Axios.defaults.withCredentials=true;

 Vue.filter('converDate',function(value) {
     return Moment(value).format('YYYY-MM-DD');
 });

 Vue.filter('currency',currency);

9.mongoose update   $pull刪除字段對應數組中的對象

10.跳轉頁面

this.$router.push({path: '/user/item?addressId='+ temp})

11. vuex 統一狀態管理

在項目中如購物車的數量等需要實時的在各個單頁面統一更新,若利用父子組件通信傳值,則較不方便,若有一個全局的變量來進行更新,則方便許多,在mutations 中通過commit 方法修改變量值,需要用到的數據封裝成一個對象payload,一起傳過去。

npm install vuex --save
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

 在vue 中註冊。

var store=new Vuex.Store({
    state:{
        count:0
    },
    mutations:{
        getCount(state,payload){
            if(payload.flag=='add'){
                console.log('數量count:'+store.state.count);
                console.log('數量傳參:'+payload.count);
                store.state.count+=payload.count;
                console.log('數量結果:'+store.state.count);
            }
            else if(payload.flag=='minus'){
                 store.state.count-=payload.count;
            }
        }
    }
})

new Vue({
    el:'#myapp',
    store,
    router: router,
    render: function(create){
        return create(App);
    }
})

在組件footer.vue 中

methods:{
                getCart(){
                     this.$ajax.get('/users/cart').then((response)=>{
                        if(response){
                          var re=response.data;
                          if(re.status=='1'){
                              this.cartList=re.result.cartList;
                              console.log('購物車數量:'+re.cartCount);
                              var payload={
                                  flag:'add',
                                  count: re.cartCount
                              }
                              this.$store.commit("getCount",payload);

                          }
                        }
                        else{
                          console.log('獲取購物車失敗!');
                        }
                     })
                  }

12. 樣式上需要注意的點:

在 style 中引入css ,scss 文件 @import  '../../style/mixin' ; 分號分割;

定義 animation動畫  @keyframes tipMove{

0%{ transform: scale(1)}

}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章