最新vue+vant移动端电商项目

今天为大家带来一个Vue+VantUi完成的一个一个移动端电商项目,供大家学习和参考.
源码已上传到码云上面https://gitee.com/jiuyueqi/vyx,
如果有需要源码或者接口文档的欢迎评论区留言,看到后会第一时间进行回复

废话不多说先上效果图!!!
在这里插入图片描述
在这里插入图片描述

下面开始让我为大家介绍一下该项目用到的知识点及核心代码

一、Vant

官网地址:https://youzan.github.io/vant/#/zh-CN/quickstart

通过vscode打开项目,使用 ctrl+~ 打开终端。我们通过yarn来安装vant:

npm  add vant

1.1、引入方式

VantUI支持全局引入与按需引入,我们选用按需引入。

1.2、按需引入自动化

按需引入又分为自动按需引入与手动按需引入,我们选用自动按需引入:

yarn add babel-plugin-import

安装完成后,打开 babel.config.js 写入:

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
}

怎样验证安装成功了呢?我们引用一个Button组件,看看效果就知道了。

Button组件的文档:https://youzan.github.io/vant/#/zh-CN/button#dai-ma-yan-shi

main.js 中:

import { Button } from 'vant';
Vue.use(Button);

Home.vue 中:

<van-button type="primary">主要按钮</van-button>

运行 yarn serve 可以看到:

如此,我们成功了!

1.3、路径提示配置

  • 安装 Path Intellisense插件
  • 打开设置 - 首选项 - 搜索 Path Intellisense - 打开 settings.json ,添加:
 "path-intellisense.mappings": {
     "@": "${workspaceRoot}/src"
 }
  • 在项目 package.json 所在同级目录下创建文件 jsconfig.json
{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "allowSyntheticDefaultImports": true,
        "baseUrl": "./",
        "paths": {
          "@/*": ["src/*"]
        }
    },
    "exclude": [
        "node_modules"
    ]
}
  • 重启vscode

1.4、Vant组件独立化编写

如果我们所有要用到的组件都直接写在 main.js 中,那这份入口文件会很冗余,不利于维护。所以我们在 src/components 下新建 vant.js ,写入:

import Vue from 'vue'
import { Button } from 'vant';
Vue.use(Button);

main.js 中:

import '@/components/vant.js'

如此,我们所有要引入组件的代码,就在 vant.js 中来完成。
在这里插入图片描述

二、端口配置

有时候我们会开启多个服务器进行模拟,为了表面冲突,有时候我们需要更改8080端口,我们可以在根目录下新建 vue.config.js 中:

module.exports = {
    devServer: {
        port: 5000
    }
}

重新运行 yarn serve 就可以在 http://localhost:5000 中访问项目了。

三、封装axios,抽取api.js

3.1 request.js

该模块的主要功能是封装axios请求,并进行拦截器的书写
拦截器:主要用在验证登陆,携带后端要求的请求头token等

import axios from "axios"

const instance = axios.create({
  baseURL: "http://kumanxuan1.f3322.net:8001",
  timeout: 5000
})
// 两种拦截器的区别
// 封装axios拦截器,拦截的是请求,一般用在需要在请求中添加请求信息(例如:请求头)
// 路由拦截:拦截的是页面,可以决定用户有没有权利访问某个页面



// 拦截器
instance.interceptors.request.use(config => {
  // 什么时候执行的??    发请求之前执行这个函数
  // 可以判断用户有没有登录,  如果没有登录就直接return, 请求就不会执行
  // console.log("config", config); // 本次请求的一些信息
  let token = localStorage.getItem("token")
  if (token) {
    // 携带登录凭证发起请求
    config.headers["X-Nideshop-Token"] = token
  }

  return config
}, err => {
  return Promise.reject(err)
})


instance.interceptors.response.use(res => {
  // 什么时候执行的??    在接收到响应之前,在执行then之前
  // console.log("res", res); // 服务器响应的一些信息


  return res; // 返回的这个res  被then方法的res形参接收了
}, err => {
  return Promise.reject(err)
})

export default instance

3.2 api.js

api.js 用来管理请求

在这里插入图片描述

3.3、发起请求

Home.vue 中:

created(){
    GetHomeLists()
        .then(res=>{
            if(res.errno == 0){
                console.log(res.data)	// 成功拿到所有首页数据
            }
        })
}

四、路由拦截,路由守卫

在实际开发过程中我们往往需要进行路由的拦截,主要是token,如在未登录之前我们不允许进行购物车页面的访问,不许许直接查看收藏商品等功能

// 前置路由守卫
router.beforeEach((to, from, next) => {
  // 要去往的路由对象
  // console.log("to", to);
  // 从哪里来的路由
  // console.log("from", from);
  // next放行  可以顺利到达要去的路由



  // 获取登录凭证
  let token = localStorage.getItem("token");
  if (to.path == "/cart") { // 表示去往购物车页面
    // 判断有没有登录,判断token是否存在
    if (token) {
      next()
    } else {
      // 表示没有登录
      Vue.prototype.$toast("请先登录")
      setTimeout(() => {
        next("/user") // 跳转到user路由
      }, 1000);
    }
    // return
  }


  next()
})

五、跨域配置

我们对 vue.config.js 进行配置:

module.exports = {
    devServer: {
        port: 5000,
        proxy: {
            '/api': {
                target: "http://kumanxuan1.f3322.net:8001/",
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }
}

由于配置文件修改了,这里一定要记得重新 npm run serve !!

六、登陆逻辑,本地存储

 created() {
    // 组件刚创建的时候需要判断用户是否登录,判断localStorage有没有token值
    // 如果有就应该天上用户信息
    let token =  localStorage.getItem("token")
    if (token) {
      // 表示已经有登录状态,就要渲染用户信息
      let userInfo = JSON.parse(localStorage.getItem('userInfo'));
      this.nickname = userInfo.nickname;
      this.avatarSrc = userInfo.avatar;
    }
  },
  methods: {
     onSubmit(values) {
      // console.log('submit', values);

      let username = values["用户名"];
      let pwd = values["密码"];
      GoLogin({
        username,
        pwd
      }).then(res=> {
        // console.log(res.data);
        if(res.data.errno == 0){
          console.log(res.data);
          // 登录成功了
          // 1.提示框提示登录成功
          this.$toast.success('登录成功');
          // 2.把token保存到本地存储
          localStorage.setItem("token", res.data.data.token);
          localStorage.setItem("userInfo", JSON.stringify(res.data.data.userInfo));
          // 3.1s后关闭模态框
          setTimeout(() => {
            this.isShowModal = !this.isShowModal;
            // 4.把拿到的userInfo填写到页面上
            this.nickname = res.data.data.userInfo.nickname;
            this.avatarSrc = res.data.data.userInfo.avatar;
          }, 1000);
          
        }
      })
    },
    openModal() {
      // 判断用户是否登录,如果登录就直接return
      // 没有登录就取反
      let token = localStorage.getItem("token")
      if(token) {
        return
      }
      this.isShowModal = !this.isShowModal
    }
  },
}

七、transition和Vuex的使用

7.1 transition

  • 众所周知,如今的网站越来越多,页面也越来越秀,一个好看的页面往往可以提升用户的使用体验,这也就使我们经常会做一些小的细节来增加页面的效果,而transition就可以做一些过度效果,vue官就给我们提供了一些钩子函数来让我们进行这一操作
  • vant组件库也为我们提供了现成的组件
// Vue官网的方式
 .slide-enter, .slide-leave-to {
    // 过渡之前的样式写在这里
     right: -100%;
  }
  .slide-enter-active,.slide-leave-active  {
    // 过渡属性写在这里
    transition: all .3s;
  }
  .slide-enter-to, .slide-leave {
    // 过渡之后的样式写在这里
     right: 0;
  }
// vant提供的方式
 <transition name="van-slide-right">
        <router-view></router-view>
 </transition>

7.2 Vuex

安装vuex:

npm vuex

在 src 下新建 store/index.js ,用来控制弹出层是否显示:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    isShowPopupShow: false
  },
  mutations: {
    changeIsShowPopupShow(state, payload) {
      state.isShowPopupShow = payload
    }
  },
  actions: {},
  modules: {}
})

main.js 中:

...
import store from '@/store/index.js'

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

Home.vue 中:

<search @showpopup="$store.commit('togglePopup', true)"></search>

<van-popup v-model="$store.state.showPopup" position="right" :style="{ height: '100%', width: '90%' }">
    <sub-popup></sub-popup>
</van-popup>

八、部分开发小技巧

8.1、Actions中获取State的值

可以在 {commit} 之后追加 rootState

getGoodsList({ commit, rootState }) {
      GetSearchGoodsList({
        params: {
          keyword: rootState.searchVal,
          ...
        }
      }).then(res=>{
        ...
      })

8.2、快速修改某个数组中一个或多个对象的属性名

先进性深拷贝,再做替换:

JSON.parse(JSON.stringify(data).replace(/name1/g, 'new_name1').replace(/name2/g, 'new_name2').replace(/name3/g, 'new_name3')...)

replace可以重复链式编程,name1表示旧属性名,new_name表示新属性名

8.3、样式深度修改

如果你在开发中,碰到vantui的样式你无法替换,可以尝试在类名前面加 /deep/

section{
    /deep/.box{
        color: red;
    }
}

8.4、v-model与state

理论上,修改state的值,唯一的途径是通过mutations。所以v-model直接使用state的值会出现问题,因此,我们可以借助computed属性来解决这个场面:

// store中:
const store = new Vuex.Store({
	state: {
		val: "你好,世界"
	},
    mutations: {
        changeVal(state, payload){
            state.val = payload;
        }
    }
})

// 组件中:
<input v-model="value" />
<script>
export default {
    computed: {
        value: {
            get(){
                return this.$store.state.val;
            },
            set(val){
                this.$store.commit("changeVal", val);
            }
        }
    }
}
</script>

8.5 重复点击路由报错问题(官方bug)

在route目录下的index.js中加入以下代码即可解决

const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function (location) {
  return originalPush.call(this, location).catch(err => {})
}
  • 50
    点赞
  • 185
    收藏
    觉得还不错? 一键收藏
  • 38
    评论
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值