您现在的位置:首页 >> 前端 >> 内容

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站

时间:2017/2/13 9:21:43 点击:

  核心提示:首页如果觉得不错,给github源码点个赞吧QAQ前言这篇文章是总结自己写项目时的思路,遇到的问题,和学到的东西,本文只截取一部分来讲,源码已奉上,觉得项目还行的点个赞吧,谢谢一、搭建环境安装vue-...

首页

如果觉得不错,给github源码点个赞吧QAQ

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站

前言

这篇文章是总结自己写项目时的思路,遇到的问题,和学到的东西,本文只截取一部分来讲,源码已奉上,觉得项目还行的点个赞吧,谢谢

一、搭建环境

安装vue-cli

npm install -g vue-cli

创建webpack项目

vue init webpack vogue
cd vogue

安装依赖

npm install

安装vue-router
npm install vue-router --save-dev

安装vuex
npm install vuex --save-dev

运行
npm run dev

二、目录结构

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站

components中是所有页面组件 store中的index.js存放了vuex状态管理的东西,此处本应分成actions.js,mutations.js,getters.js的,可是我试了很多次没成功,还是将他们放在一个文件中,显得有点冗余了,这点失误了,会找原因的 static中存放了图片,图片是压缩了的,网站是https://tinypng.com/,还存放了字体,和一点css,css放在这里有一个原因就是,我想给某个元素设置background时,将style写在static里才行。 dist文件是后来npm run build后生成的,生成的dist中的index.html中的link都是没有加引号的,我自己加上才可以直接运行

三、项目开发

开发过程中,页面是一个一个写的,不过还是要先确定路由,路由嵌套

main.js

先说说路由吧,写在了main.js中,直接上图
一个vue2.0+vuex+vue-router搭建的单页潮流购物网站

文章开头有首页,home的路径就是‘/home’,这里路由嵌套,用‘:id’来识别,Brands.vue组件在后文中会解释如何得到id,home页的八个导航,分别导向‘/home’,‘/news’,’/collections’,’/shop’,’/home/clot’,’/home/madness’,’/home/bape’,’/home/assc’,购物车导向’/cart’,’login"register’导向‘/login’,’/newsarticle’是在news组件中导向的,‘/shoppingitem’是shop组件中导向的

App.vue

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站
一个vue2.0+vuex+vue-router搭建的单页潮流购物网站
v-for列表渲染的数据如left_navs和contents均来自state
对象迭代

    

{{ index }}. {{ key }} : {{ value }}

如何得到state中的数据

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

在布局上,我的思路是:首页三行,上下定高,中间自适应高度,于是在app.vue的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;
            }

      }
   }

然后中间那行用的三栏布局,左右定宽中间自适应宽度,再设置一个min-height不免得将中间的轮播弄来没有了,具体见css

细节:其中用data中的scroll,用来显示可以让页面一键划到顶端的按钮,滑动动画代码如下

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

    },

这里比较坑的地方就是document.documentElement.scrollTop和document.documentElement.scrollTop需要注意

Home.vue

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站vcC4tcRob21lo6xjbG90o6xtYWRuZXNzo6xiYXBlo6xhc3NjtrzT0NXiuPbX6bz+o6w8L3A+DQo8aDMgaWQ9"homefirstvue">HomeFirst.vue

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站
这里有一个焦点轮播效果,开始思考的时候没有思路,但是我参照了一下https://segmentfault.com/a/1190000007010410,才有了思路,并完善了它,但是效果还没有预想的好,这个还需要改进,通过translate来改变位置,shufflingIndex来记录当前的index

 methods:{

      caculateIndex(){ //计算上一个元素和下一个元素的index
        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();
      },
      //向前面移动
      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)  
      },
      //向后面移动
      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
        //点击圆点,就相当于点多少次左右键
        if(this.shufflingIndexindex){

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

                this.interval_timer=setInterval(function(){
                    if(self.shufflingIndex==index){
                        self.clear()
                    }else{
                        self.shufflingIndex--;
                        self.caculateIndex();
                    }
                    //必须要用if,else来clear
                },200)



        }

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

Shop.vue

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站

    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)//改变进入商品
                }
            }

每个商品被点击时都要改变进入的是哪个商品,changeSelectedItem来完成,这个页面想法来源于1626潮牌网,觉得挺好看的,于是自己写了下来,尤其是mouseover显示的是否喜欢,处理的还是可以,不过chrome和Firefox还是会有闪烁的效果没有处理好

shoppingitem.vue

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站
这个组件中重要的就是数量的增减,因为每个商品都有一个对象存储数据,并且加入购物车还需要判断购物车中是否有相同信息的商品,还有点击加入购物车后直接跳转到购物车页面,方法如下

    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中的方法如下*

    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={};
        },

添加到购物车中的方法中,我用try,catch来跳出forEach循环,还有这句state.selectedItem={};如果state.selectedItem是直接引用别的对象,那么另一个对象也会跟着改变,为了避免引用,我用了如下方法

    //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

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站
在created(){}中用this.route.params.id来得到进入那个路由,因为这四个brand布局样式什么的大致都一样,然后watch来检测this.route.params.id的改变,以此来getIntro也就是每个brand的数据

组件的介绍大致就是这些

四、Vuex

我在vuex这里没有做好,状态和数据应该分开,而且actions,mutations,getters,state,应该分开,不然太冗余了

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
这个状态自管理应用包含以下几个部分:
state,驱动应用的数据源;
view,以声明方式将state映射到视图;
actions,响应在view上的用户输入导致的状态变化。

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站

一个vue2.0+vuex+vue-router搭建的单页潮流购物网站

index.js中的state

大概罗列一点

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中的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
            }
        },
    ]

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutations 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

index.js中的actions

    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 类似于 mutation,不同在于:

Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。

index.js中的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
        }
    ]

有时候我们需要从 store 中的 state 中派生出一些状态,或用于得到信息

五、总结

自己写的这个项目,蛮有收获的,遇到了问题到处问,都解决的差不多了,
下面罗列了一些收货和本项目的不足

Firefox中不支持 table 的 min-height CSS 的话 考虑用 normalize.css解决不同浏览器初始样式不一样的问题 css 的命名啥的可以参考一下 BEM 的命名规范 代码组织有点杂乱 vuex只要专心做页面状态管理,尽量不要掺杂页面数据 此处的isAll是从state中get到得数据,可以被改变,我自己尝试得到的这个结论 轮播还需要改进 第一次在gh-pages中显示时,发现图片加载太慢 ,于是我把图片压缩了 在用git上传代码是出过差错,解决了。

最后感谢您能阅读到这里,本人小白,努力学习中,献丑了。

Tags:一个 个V VU UE 
作者:网络 来源:github_370