A vue2.0 + vuex + vue-router built single-page fashion shopping site

Project demo address
github source address

Home

I feel good, to my github source point of a praise it QAQ

image description

Foreword

This article is a summary of their own ideas when writing the project, problems encountered, and what I've learned, this is only part of the interception is concerned, the source code has been served, that the point of a project okay praise it, thank you

First, set up environment

  • Installation vue-cli

npm install -g vue-cli

  • Creating webpack project

vue init webpack vogue
cd vogue

  • Installation depends

npm install

  • Installation vue-router

npm install vue-router --save-dev

  • Installation vuex

npm install vuex --save-dev

  • run

npm run dev

Second, the directory structure

image description

  • components are all page components

  • The index.js store to store things vuex state management, where this should be divided into actions.js, mutations.js, getters.js, but I tried many times without success, or put them in a file, It seemed a bit redundant, and this mistake will be to find a cause of

  • stored in a static picture, the picture is compressed, the site is https://tinypng.com/ time, also holds the font, and a little css, css is placed here for a reason, I want to set the background of an element , written in the style static in the job.

  • dist file is then generated after npm run build, dist generated index.html in the link are not quoted, plus I can directly run

Third, project development

The development process, a page is written, but the thing is to determine the routing, routing nesting

main.js

First talk about the routing of it, written in the main.js in directly on the map
image description

Beginning of the article there are home, home is the path '/ home', where the route nest with ': id' to identify, Brands.vue components later will explain how to get the eight navigation id, home pages, respectively oriented ' / home ',' / news', '/ collections',' / shop ',' / home / clot ',' / home / madness', '/ home / bape', '/ home / assc', cart-oriented '/ cart', 'login | register' guide '/ login', '/ newsarticle' is oriented in the news component, '/ shoppingitem' shop assembly is guided

App.vue

image description
image description
v-for list of rendering data such as left_navs from state and contents are
subject iteration

<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }} : {{ value }}
</div>

How to get the data in the state

 import {mapGetters} from 'vuex'
    computed:{
    ...mapGetters({
      show:'getShow',
      items:'getFootItems',
      cart:'getCart',
      brands:'getBrands',
      left_navs:'getLeft_nav'
    })
  },

On the layout, my idea is: First three lines, set the upper and lower high, middle highly adaptive, then set the event delegate in app.vue's created ()

    var self=this;
      window.onload=()=>{
        this.$store.dispatch('change_hw',{
          h:document.documentElement.clientHeight||document.body.clientHeight,
          w:document.documentElement.clientWidth||document.body.clientWidth
        })
      }
      window.onresize=()=>{
        if(self.timer){
          clearTimeout(self.timer)
        }
        self.timer=setTimeout(function(){
          self.$store.dispatch('change_hw',{
            h:document.documentElement.clientHeight||document.body.clientHeight,
            w:document.documentElement.clientWidth||document.body.clientWidth
          })
        },100)
      }
      window.onscroll=()=>{
         var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
            if(scrollTop>10){
              this.scroll=true;
            }else{
              this.scroll=false;
            }
        
      }
   }

Then the middle of the line with a three-column layout, around a fixed width adaptive intermediate width, then set a min-height lest not to stir up the intermediate wheel there is no particular see css

Details: wherein Scroll with the data, to display a page that allows a designated key to the top of the button, as the slide animation code

scrolltoTop:()=>{
      if(document.documentElement.scrollTop){
        var scrollTop=document.documentElement.scrollTop
        var step=scrollTop/30;
        var now=scrollTop-step;
        var i=0;
        var time=setInterval(function(){
          i++;
          if(i>32){
            clearInterval(time)
          }
          document.documentElement.scrollTop=now;
          scrollTop=document.documentElement.scrollTop
          now=scrollTop-step;
        },10)
      }else if(document.body.scrollTop){
        var scrollTop=document.body.scrollTop
        var step=scrollTop/30;
        var now=scrollTop-step;
        var i=0;
        var time=setInterval(function(){
          i++;
          if(i>32){
            clearInterval(time)
          }
          document.body.scrollTop=now;
          scrollTop=document.body.scrollTop
          now=scrollTop-step;
        },10)
      }
      
    },

Comparison of the pit is the place to note that document.documentElement.scrollTop and document.documentElement.scrollTop

Home.vue

image description
Here are brands of style, that is home navigation bar, clot, madness, bape, assc have this component,

HomeFirst.vue

No. 2.21 Modify
again changed under the carousel, to achieve unlimited carousel by changing the left, the following ideas:

<div class="wrapper-content" :class="{wrapper_trans:isTrans}" :style="{width:originalData.img_width*(originalData.num+2)+'px',height:originalData.img_height+'px',left:-originalData.img_width+'px'}" ref="wrapperContent">
    <img class="wrapper-content_img" alt="4" :src="'../static/images/home_4.jpg'" :style="{width:originalData.img_width+'px',height:originalData.img_height+'px'}"/>
    <img class="wrapper-content_img" alt="1" :src="'../static/images/home_1.jpg'" :style="{width:originalData.img_width+'px',height:originalData.img_height+'px'}"/>
    <img class="wrapper-content_img" alt="2" :src="'../static/images/home_2.jpg'" :style="{width:originalData.img_width+'px',height:originalData.img_height+'px'}"/>
    <img class="wrapper-content_img" alt="3" :src="'../static/images/home_3.jpg'" :style="{width:originalData.img_width+'px',height:originalData.img_height+'px'}"/>
    <img class="wrapper-content_img" alt="4" :src="'../static/images/home_4.jpg'" :style="{width:originalData.img_width+'px',height:originalData.img_height+'px'}"/>
    <img class="wrapper-content_img" alt="1" :src="'../static/images/home_1.jpg'" :style="{width:originalData.img_width+'px',height:originalData.img_height+'px'}"/>
</div>

A total of four images, plus a before and after, become six, when the scroll back to fifth, index of 4, the next scroll, scroll to jump immediately after the end of the sixth second, index still 3. Slide forward the same reason

methods as follows

export default {
        data (){
            return {
                originalData:{
                    img_width:350,
                    img_height:350,
                    btn_width:40,
                    btn_height:40,
                    num:4,
                    delay:300
                },
                isTrans:true,//因为到最后一张图片,index为1时,需要立即跳到第二张index也为1的图片,这个用来是否给出transition
                index:1,
                timer:null,//setInterval
                clickdelay:false//用来防止连续点击
            }
        },
        computed:{
            ...mapGetters({
                hw:'getHW'
            }),
             home_first_width:function(){
                 return parseInt(this.hw.w)-400;            
            },
            home_first_height:function(){
                
                var a= parseInt(this.hw.h)-200
                return a<389?389:a
            },
            home_first_height_margin:function(){
                return parseInt(this.home_first_height-300)/2
            }
        },
        methods:{
                next(){
                    if(this.clickdelay){
                        return 
                    }
                    this.clickdelay=true
                    if(this.index==this.originalData.num){
                        this.index=1
                    }else{
                        
                        this.index+=1
                    }
                    this.animate(this.originalData.img_width)
                    
                },
                prev(){
                    if(this.clickdelay){
                        return 
                    }
                    this.clickdelay=true
                    if(this.index==1){
                        this.index=this.originalData.num
                    }else{
                        this.index-=1
                    }
                    this.animate(-this.originalData.img_width)    
                },
                animate(offset){
                    var node=this.$refs.wrapperContent
                    var self=this;
                    var left=parseInt(node.style.left)-offset
                    this.isTrans=true
                    node.style.left=left+'px'
                    setTimeout(function(){
                        if(left<-(self.originalData.num*self.originalData.img_width)){
                            self.isTrans=false
                            node.style.left=-self.originalData.img_width+'px'
                            self.clickdelay=false //当到达最后一张图片时 
                        }
                        if(left>-100){
                            self.isTrans=false
                            node.style.left=-self.originalData.num*self.originalData.img_width+'px'
                            self.clickdelay=false //当到达第一张图片时  
                        }
                    },this.originalData.delay)
                },
                play(){
                
                    var self=this;
                    this.timer=setInterval(function(){
                        self.next()
                    },2000)
                },
                stop(){
                    this.clickdelay=false//用来防止连续点击
                    clearInterval(this.timer)
                    this.timer=null
                },
                turnTo(flag){
                    if(flag==this.index){
                        return
                    }else{
                        var offset=(flag-this.index)*this.originalData.img_width
                        this.index=flag
                        this.animate(offset)

                    }

                }
            },
            
            mounted(){
                /*下面是判断过渡动画是否完成*/ 
                var node=this.$refs.wrapperContent
                var transitions = {
                     'transition':'transitionend',
                     'OTransition':'oTransitionEnd',
                     'MozTransition':'transitionend',
                     'WebkitTransition':'webkitTransitionEnd'
                     }
                     var self=this
 
               for(var t in transitions){

                   if( node.style[t] !== undefined ){
                       var transitionEvent=transitions[t];
                   }
               }
               transitionEvent && node.addEventListener(transitionEvent, function() {
                       self.clickdelay=false              
                  });
               this.play()
            },
        created(){
            this.$store.dispatch('changeShow','home')
        }
    }

Shop.vue

image description

methods:{
            changeLike(index){
                this.$store.dispatch('changeLike',index)//改变是否喜欢
            },
            changeFlagTrue(index){
                this.$store.dispatch('changeFlagTrue',index)//改变是否显示喜欢
            },
            changeFlagFalse(index){
                this.$store.dispatch('changeFlagFalse',index)//改变是否显示喜欢
            },
            changeSelectedItem(index){
                this.$store.dispatch('changeSelectedItem',index)//改变进入商品
            }
        }

Each product must be changed which click into the commodity, changeSelectedItem to complete, this idea comes from page 1626 Tide brand network, I feel very good to see, then wrote down, especially if you like mouseover display, processing still can, but there will still be flashing chrome and Firefox did not deal with the effect of

shoppingitem.vue

image description
The important thing is the number of components increase or decrease, because each item has an object to store data, and ADD TO CART also need to determine whether there is the same information in their shopping carts, and jump directly to click Add to Cart shopping cart page, as follows

methods:{
            changeSize(index){
                this.$store.dispatch('changeSize',index)
            },
            changeColor(num){
                this.$store.dispatch('changeColor',num)
            },
            changeNumSub(){
                if(this.item.num>1){
                    this.$store.dispatch('changeNumSub')
                }
                
            },
            changeNumAdd(){
                if(this.item.num<8){
                    this.$store.dispatch('changeNumAdd')
                }
            },
            addToCart(){
                if(!!this.item.color&&!!this.item.size){
                    this.$store.dispatch('addToCart')
                }
            }
        }

The method is as follows index.js

ADD_TO_CART(state){
        var cart=state.cart;
        var thing=mutations.clone(state.selectedItem);
        //查看购物车是否已经有相同的商品,信息都一样
        
        if(!cart.length){
            cart.push(thing)    
        }else{
            var flag=cart.some(function(e){
                return e.color==thing.color&&e.size==thing.size&&e.src==thing.src
            })
            try{
                if(!flag){
                    cart.push(thing);
                    throw new Error("can't find")
                }
                cart.forEach(function(e,index){
                    if(e.color==thing.color&&e.size==thing.size&&e.src==thing.src){
                        cart[index].num+=thing.num;
                        foreach.break=new Error("StopIteration");
                    }
                })    
            }catch(e){
                //用于跳出循环
            }
            
        }
        state.selectedItem={};
    },

Add to shopping cart approach, I try, catch forEach to jump out of circulation , as well as the phrase state.selectedItem = {}; if state.selectedItem is a direct reference to another object, another object will also change, In order to avoid quoted, I use the following method



//js复制对象
    clone(myObj){
      if(typeof(myObj) != 'object') return myObj;
      if(myObj == null) return myObj;
  
      var myNewObj = new Object();
      
      for(var i in myObj)
        myNewObj[i] = mutations.clone(myObj[i]);
      
      return myNewObj;
    },

Brands.vue

image description
In created () {} with this. $ Route.params.id to obtain access to that route because four brand what layout styles are substantially the same, and then watch to detect this. $ Route.params.id of change, in order to getIntro that is, data for each brand of

Introduction of these components is roughly

Four, Vuex

I did not do a good job here in vuex, status, and data should be separated, and actions, mutations, getters, state, should be separated, or too redundant the

Vuex is a specially developed for Vue.js application state management. It uses the status of all components centralized storage management application, and a corresponding state rules to ensure a predictable manner changed. Vuex Vue is also integrated into the official commissioning tool devtools extension, provides a time-travel, such as zero-configuration debugging, a snapshot of the state of import and export and other advanced debugging features.
This state from the management application includes the following sections:
state, driving the application data source;
view, declaratively mapped to the view state;
Actions, a user input in response to a state change caused on the view.

clipboard.png

clipboard.png

The state index.js

Probably a little list

const state={
    loginway:'',
    show:'home',
    clientheight:0,
    clientwidth:0,
    footItems:[
        {title:'ABOUT US',contents:{content_1:'contact us',content_2:'about vogue'}},
        {title:'SERVICE',contents:{content_1:'payment methods',content_2:'track order'}},
        {title:'POLICY',contents:{content_1:'privacy policy',content_2:'terms & condition'}},
        {title:'FOLLOW US',contents:{content_1:'Facebook',content_2:'Instagram'}},    
    ],
    left_nav:{
        home:'home',
        news:'news',
        collections:'collections',
        shop:'shop'
    },
]

index.js of mutations

const mutations={
    CHANGE_HW(state,obj){
        state.clientwidth=obj.w;
        state.clientheight=obj.h;
    },
    CHANGE_SHOW(state,type){
        state.show=type
    },
    CHANGE_NOWBRAND(state,type){
        state.nowbrand=type+'Intro'
    },
    CHANGE_LIKE(state,index){
        state.goods[index].isLike=!state.goods[index].isLike;
        if(!state.goods[index].isLike){
            state.goods[index].likes+=1
        }else{
            state.goods[index].likes-=1
        }
    },
]

The only way to change Vuex the store is in a state of submission mutation. Vuex of mutations is very similar to: Event Type (type) of each mutation has a string and a callback function (handler). The callback function is where we actually change the status, and it will accept the state as the first parameter:

The actions index.js

const actions={
    change_hw({commit},obj){
        commit('CHANGE_HW',obj)
    },
    changeShow({commit},type){
        commit('CHANGE_SHOW',type)
    },
    changeNowbrand({commit},type){
        commit('CHANGE_NOWBRAND',type)
    },
    changeLike({commit},index){
        commit('CHANGE_LIKE',index)
    },
]

Action similar mutation, except that:

Action is submitted mutation, rather than directly change state.
Action can contain any asynchronous operation.

index.js in getters

const getters={
    getHW:function(state){
        return {
            h:state.clientheight,
            w:state.clientwidth
        }
    },
    getBrands:function(state){
        return state.brandsArr
    },
    getLeft_nav:function(state){
        return state.left_nav
    },
    getShow:function(state){
        return state.show
    }
]

Sometimes we need to derive from the store in the state in some states, or to get information

V. Summary

Write your own project, quite the harvest, has encountered a problem and asked everywhere, are almost resolved,
the following lists some of the deficiencies and receipt of the project

  • Firefox not supported in the min-height table

  • CSS, then consider using a different browser normalize.css solve the initial problem is not the same style

  • css named Han can refer to the naming convention BEM

  • A little messy code organization

  • vuex just concentrate on doing page state management, try not doped page data

  • <Input type = "checkbox" @ change = "selectAll" id = "selectAll" v-model = "isAll" /> isAll here is to get to the data obtained from the state can be changed, I try to get this in conclusion

  • Carousel also needs to be improved

  • The first display in gh-pages found image loading is too slow, so I put a picture compression

  • With git upload code made a mistake, resolved.

Finally, thank you to read here, I am white, to study in incompetence.

Reference material

Guess you like

Origin www.cnblogs.com/baimeishaoxia/p/12551248.html