A One-page Trend Shopping Website Built by vue2.0+vuex+vue-router

Keywords: Vue npm github xml

Project demo address
github source address

home page

If you think it's good, give github source code a compliment QAQ

Preface

This article is a summary of my own ideas, problems encountered, and things learned when writing the project. This article only intercepts a part of it. The source code has been provided. I think the project is still working. Thank you.

1. Building the Environment

  • Install vue-cli

    npm install -g vue-cli

  • Create a webpack project

vue init webpack vogue
cd vogue
  • Installation dependency

    npm install

  • Install vue-router
    npm install vue-router --save-dev

  • Install vuex
    npm install vuex --save-dev

  • Function
    npm run dev

II. Directory Structure

  • Components are all page components
  • The index.js in the store stores the vuex state management stuff, which should be divided into actions.js,mutations.js,getters.js, but I tried many times unsuccessfully, or put them in a file, which seems a little redundant, this error, will find the reason.
  • static stores pictures, which are compressed, and the website is https://tinypng.com/ It also stores fonts and a little bit of css. One reason why CSS is here is that when I want to set a Backgroundfor an element, I write style in static.
  • The dist file was generated after npm run build. The link s in index.html of the generated dist are not quoted, so I can add them myself to run directly.

III. Project Development

In the development process, the pages are written one by one, but it is still necessary to determine the routing, routing nesting.

main.js

Let's start with routing. It's written in main.js, directly above.

At the beginning of the article, the path of home is'/ home', where the route is nested and identified by': id'. Brands.vue component will explain how to get the id, eight navigation of the home page, which are directed to'/ home','/ news','/ collections','/ shop','/ home/clot','/ madness','/ home/bape','/ home/assc', shopping cart cart orientation respectively. ’ login|register'orientates'/ login','/ newsarticle'is orientated in the news component,'/ shopping gitem' is orientated in the shop component.

App.vue



Data rendered by the v-for list, such as left_navs and contents, are from state
Object iteration

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

How to get the data in state

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

In terms of layout, my idea is to set the event delegation in create () of app.vue by setting three lines of the front page, setting the height up and down, and adjusting the height in the middle.

    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 three-column layout of the middle line, left and right width, middle adaptive width, and set a min-height will inevitably make the middle of the rotation lost, see css specifically.

Details: scroll in data is used to display buttons that allow a page to be scratched to the top. The sliding animation code is as follows

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)
      }

    },

The places where we compare pits are document.documentElement.scrollTop and document.documentElement.scrollTop.

Home.vue


Here we give the brands style, that is to say, the navigation bar home, clot, madness, bape, assc all have this component.

HomeFirst.vue


Here's a focus on the effect of rotation. There's no way to start thinking about it, but I took a look at it. https://segmentfault.com/a/1190000007010410 Only then has the thought, and consummates it, but the effect has not been anticipated good, this also needs to be improved, through translation to change the location, shuffling index to record the current index.

 methods:{

      caculateIndex(){ //Calculate the index of the previous element and the next element
        this.preIndex = this.shufflingIndex - 1 < 1 ? 4: this.shufflingIndex - 1;
        this.nextIndex = this.shufflingIndex + 1 > 4 ? 1 : this.shufflingIndex + 1;
      },
      autoScroll(){
        var self=this
        this.clear()
        this.openNext=false;
         this.openPre=true;
        this.interval_timer=setInterval(self.autoChange,2000)
      },
      autoChange(){
        if(this.shufflingIndex == 4){
            this.shufflingIndex = 1;
        }else{
            this.shufflingIndex++;
        }   
        this.caculateIndex();
      },
      //Move forward
      click_pre(){

        if(this.timeout_timer){
            clearTimeout(this.timeout_timer)
        }
        var self=this;
        self.openNext=false;
            self.openPre=true;
        this.timeout_timer=setTimeout(function(){

            self.autoChange();
        },300)  
      },
      //Move back
      click_next(){

        if(this.timeout_timer){
            clearTimeout(this.timeout_timer)
        }
        var self=this;
        self.openNext=true;
            self.openPre=false;

        this.timeout_timer=setTimeout(function(){
            self.shufflingIndex=self.shufflingIndex==1?4:self.shufflingIndex-1
            self.caculateIndex()
        },300)

      },
      clear(){
        if(this.interval_timer){
            clearInterval(this.interval_timer)
        }
      },
      round(index){
        var self=this
        //How many times do you click on a dot?
        if(this.shufflingIndex<index){
            this.openNext=false;
            this.openPre=true;
                this.interval_timer=setInterval(function(){
                    if(self.shufflingIndex==index){
                        self.clear()        
                    }else{
                        self.shufflingIndex++;
                        self.caculateIndex();
                    }
                    //if, else must be used to clear
                },200)


        }else if(this.shufflingIndex>index){

            this.openNext=true;
            this.openPre=false;

                this.interval_timer=setInterval(function(){
                    if(self.shufflingIndex==index){
                        self.clear()
                    }else{
                        self.shufflingIndex--;
                        self.caculateIndex();
                    }
                    //if, else must be used to clear
                },200)



        }

      }
},
created(){
    this.$store.dispatch('changeShow','home')
    this.caculateIndex();
    this.autoScroll();
}

Shop.vue

    methods:{
                changeLike(index){
                    this.$store.dispatch('changeLike',index)//Change whether you like it or not
                },
                changeFlagTrue(index){
                    this.$store.dispatch('changeFlagTrue',index)//Change whether to show liking
                },
                changeFlagFalse(index){
                    this.$store.dispatch('changeFlagFalse',index)//Change whether to show liking
                },
                changeSelectedItem(index){
                    this.$store.dispatch('changeSelectedItem',index)//Changing access to goods
                }
            }

When each item is clicked, it changes which item it enters. ChangeSelected Item completes this page. The idea of this page comes from 1626 Chaobai. It feels good. So I wrote it down. Especially whether mouseover displays like it or not, it can be processed. However, chrome and Firefox still have flickering effect, which is not handled well.

shoppingitem.vue


The most important thing in this component is the increase or decrease of quantity, because each item has an object to store data, and adding shopping cart also needs to determine whether there are goods with the same information in the shopping cart, and click on the item to join the shopping cart and jump directly to the shopping cart page.

    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')
                    }
                }
            }
   *index.js The method is as follows*

    ADD_TO_CART(state){
            var cart=state.cart;
            var thing=mutations.clone(state.selectedItem);
            //Check to see if the shopping cart already has the same goods and the information is the same.

            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){
                    //Used to jump out of the loop
                }

            }
            state.selectedItem={};
        },

In the method added to the shopping cart, I use try, catch to jump out of the forEast loop, and the sentence state.selectedItem={}; if state.selectedItem is a direct reference to another object, then another object will change. To avoid reference, I use the following method

    //js replication object
        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


In create (){}, use this.route.params.id to get the entry route, because the four brand layout styles are roughly the same, and then watch to detect the change of this.route.params.id, so getIntro is the data for each brand.

That's the general description of components.

Four, Vuex

I haven't done a good job here in vuex. State and data should be separated, and actions, mutations, getters, state should be separated, otherwise it's too redundant.

Vuex is a state management model developed specifically for Vue.js applications. It uses centralized storage to manage the state of all components of an application, and ensures that the state changes in a predictable manner with corresponding rules. Vuex is also integrated into Vue's official debugging tool devtools extension, providing advanced debugging functions such as zero-configuration time-travel debugging, status snapshot import and export.
This state self-management application consists of the following parts:
state, the data source that drives the application;
View, which maps state to view declaratively;
actions, which respond to changes in state caused by user input on view.

state in index.js

Maybe a little

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'
        },
    ]

mutations in index.js

    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 the state in Vuex's store is to commit mutation. Variations in Vuex are very similar to events: each mutation has a string of event types and a handler. This callback function is where we actually make state changes, and it accepts state as the first parameter:

actions in 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 is similar to mutation, except that:

Action submits mutation s rather than changing state directly.
Action can contain any asynchronous operation.

getters in index.js

    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 some state from the state in the store, or use it to get information.

Five, summary

I wrote this project by myself, which was quite fruitful. When I met problems and asked everywhere, I almost solved them.
Here are some receipts and shortcomings of this project

  • min-height does not support table s in Firefox
  • Consider using normalize.css to solve the problem that different browsers have different initial styles.
  • What is the naming of css? Refer to the naming specification of BEM.
  • Code organization is a bit messy
  • As long as vuex concentrates on page state management, try not to mix up page data
  • <input type="checkbox"@change="selectAll" id="selectAll" v-model="isAll"/> isAll here gets data from the state and can be changed. This conclusion I tried to draw is that the input type="checkbox"@change="selectAll" id="selectAll" v-model="isAll"/> isAll here gets data from the state and can be changed.
  • Rotation needs improvement
  • The first time I showed it in gh-pages, I found that the image loading was too slow, so I compressed the image.
  • There was a mistake in uploading code with git, which was solved.

Finally, thank you for reading here, I Xiaobai, hard work, ugly.

Reference material

Posted by NiallThistle on Mon, 25 Mar 2019 11:30:29 -0700