一. Vue CLi

1. 运行以下命令全局安装脚手架

新版本(推荐)

npm i @vue/cli -g

老版本

npm i vue-cli -g

你还可以用这个命令来检查其版本是否正确:

vue --version

2. 运行以下命令来创建一个新项目

vue create hello-world

3. 项目目录

src
  - api  -  封装数据请求
  - assets  - 资源文件夹
  - components - 自定义组件
  - filters - 自定义过滤器
  - lib - scss库
  - mixins - 混入
  - router - 路由 ---- 动态加载路由实现权限管理
  - store - 状态管理器 --- 管理状态 - 善于利用辅助函数
  - views - 页面
  - App.vue - 主页面 - 单文件组件(结构 + 表现 + 行为)
  - main.js 入口文件 - 可以引入国际化(i18n)、全局操作

vue.config.js --- vue项目配置文件 --- 根目录

3. 命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 content(内容) 和 Footer(底部) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
App.vue

<template>
  <div id="app">
    <router-view ></router-view>
    <router-view name="Footer"></router-view>
  </div>
</template>
<script>

</script>
<style>
....
</style>

./views/home/index(页面组件首页为例)

<template>
  <div class="conent">
    <h1>首页</h1>
  </div>
</template>
<script>

</script>
<style>
....
</style>

./compontents/Footer.vue(底部组件)
点击底部tabBar进行声明式导航

<template>
  <div class="Footer">
    <div>
      <ul class="box">
        <router-link to="/home" tag="li">首页</router-link>
        <router-link to="/kind" tag="li">分类</router-link >
        <router-link to="/cart" tag="li">购物车</router-link>
        <router-link to="/user" tag="li">我的</router-link >
      </ul>
    </div>
  </div>
</template>

<script>

</script>
<style>
....
</style>

./router/index.js(路由配置文件)

import Vue from 'vue'
import VueRouter from 'vue-router'
import Footer from '@/components/Footer/index'
Vue.use(VueRouter)
const routes = [
  { // 重定向
    path: '/',
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'home', 命名路由,可以用于声明式导航传参
    components: {
      default: () => import('@/views/home/index.vue'),// 路由的懒加载
      Footer: Footer
    }
  },
  {
    path: '/cart',
    name: 'cart',
    components: {
      default: () => import('@/views/cart/index.vue')
      //购物车页面这里不需要底部所以我们这没有Footer组件 !
    }
  },
  {
    path: '/user',
    name: 'user',
    components: {
      default: () => import('@/views/user/index.vue'),
      Footer: Footer
    }
  },
  {
    path: '/kind',
    name: 'kind',
    components: {
      default: () => import('../views/kind/index.vue'),
      Footer: Footer
    }
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

页面效果
注意看购物车页面是没有底部组件的
在这里插入图片描述

vue封装axios请求

import axios from 'axios'

// 1.通过当前的运行命令判断出当前的运行环境,切换请求地址
// 开发环境 + 测试环境 + 生产环境
const isDev = process.env.NODE_ENV === 'development'
// isDev  ---  true   ----  开发环境  ----  npm run serve
// isDev  ---- false   ----  生产环境  ----  npm run build

// 如果是开发环境,服务器可能是本地的,也可能是服务器上的
const baseUrl = isDev ? 'http://www.baidu.net/api' : 'http://www.baidu.com/api'

// 2.自定义axios,添加axios拦截器
const instance = axios.create({
  baseURL: baseUrl
})

// 在实例已创建后修改默认值,比如请求时需要拿到token值
// instance.defaults.headers.common['token'] = token
// 自定义超时时间
instance.defaults.timeout = 6000

// 每一次发送请求前都需要经过这里 - 添加请求拦截器
instance.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么 -- 显示loading动画,携带token信息
  const token = localStorage.getItem('token')
  config.headers.common.token = token
  return config
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

// 每一次拿到数据都需要经过这里 - 添加响应拦截器
instance.interceptors.response.use(function (response) {
  // 对响应数据做点什么 --- 关闭loading动画
  return response
}, function (error) {
  // 对响应错误做点什么
  return Promise.reject(error)
})

export default instance

import request from './index'

/**
 * 封装首页轮播图请求
 */
export function getBannerlist (params) {
  const { url } = params
  return request({
    url,
    method: 'GET'
  })
}

/**
 * 封装首页列表请求
 */
export function getProlist (params) {
  const { url, data } = params
  // return request({
  //   url,
  //   data:
  //   method: 'GET'
  // })
  return request.get(url, {
    params: data || {}
  })
}

嵌套路由

./router/index.js(路由配置文件)

 {
    path: '/user',
    name: 'user',
    components: {
      default: () => import('@/views/user/index.vue'),
      Footer: Footer
    },
    children: [
      {
        path: 'nologin',
        component: nologin
      },
      {
        path: 'loging',
        component: loging
      }
    ]
  },

在这里插入图片描述
./views/index.vue

<template>
  <div class="content">
    <h1>个人中心</h1>
    <router-view ></router-view>
  </div>
</template>

<script>

</script>

在这里插入图片描述

路由守卫

./store/index(vuex全局仓库)

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    token: localStorage.getItem('token'),
    username: localStorage.getItem('username')
  },
  mutations: {
    set_token: function (state, token) {
      state.token = token
    },
    set_username: function (state, username) {
      state.username = username
    }
  },
  actions: {
  },
  modules: {
  }
})

./views/nologin(登录页面组件)

//储存token,username信息到本地存储和vuex
 methods: {
    onSubmit (values) {
      console.log('submit', values)
      request({
        method: 'post',
        url: '/users/login',
        data: {
          tel: values.tel,
          password: values.password
        }
      }).then(res => {
        if (res.data.code === '10008') {
          alert('成功')
          this.$store.commit('set_token', res.data.data.token)
          this.$store.commit('set_username', res.data.data.username)
          localStorage.setItem('token', res.data.data.token)
          localStorage.setItem('username', res.data.data.username)
          this.$router.push('/user/loging')
        } else if (res.data.code === '10007') {
          alert('未注册')
        } else {
          alert('密码错误')
        }
      })
    }
  }

./router/index

router.beforeEach((to, from, next) => {
  // 一定要调用next()方法来resolve这个钩子
  //全局守卫判断有无token信息,路由跳转逻辑
  if (to.path === '/user') {
    console.log(store.state.token)
    if ((store.state.token)) {
      next('/user/loging')
    } else {
      next('/user/nologin')
    }
  } else if (to.path === '/user/loging') {
    if (store.state.token) {
      next()
    } else {
      next('/user/nologin')
    }
  } else if (to.path === '/user/nologin') {
    if (store.state.token) {
      next('/user/loging')
    } else {
      next()
    }
  } else {
    next()
  }
})

在这里插入图片描述

首页组件

./views/home/index

首页轮播图渲染
// 使用vant组件库
<template>
  <div class="content">
    <van-swipe :height="200" :width="300" :loop="false" class="my-swipe" :autoplay="3000" indicator-color="white"> // 轮播图
      <van-swipe-item v-for="(banner, index) in banners" :key="index"><img :src="www.baidu.com" alt="">{{banner}}</van-swipe-item>
    </van-swipe>
    <Prolist/> 
    <vueToTop bottom='100' type='4' color='red'></vueToTop> // 回到顶部的插件
  </div>
</template>

<script>
import Vue from 'vue'
import { Swipe, SwipeItem } from 'vant'
import Prolist from '../../components/Prolist'
import request from '../../api/index'
import vueToTop from 'vue-totop'
Vue.use(Swipe)// 轮播
Vue.use(SwipeItem)
Vue.use(vueToTop)
export default {
  components: {
    Prolist
  },
  data () {
    return {
      banners: []
    }
  },
  created () {
    this.getBanner() // 请求轮播图
  },
  methods: {
    getBanner: function () {
      request({
        method: 'get',
        url: '/pro/banner'
      }).then(res => {
        this.banners = res.data.data
      })
    }
  }
}
</script>
<style>
.my-swipe .van-swipe-item {
  color: #fff;
  font-size: 20px;
  line-height: 150px;
  text-align: center;
  background-color: #39a9ed;
}
img {
  height: 100%;
  width: 100%;
}
</style>

首页Prolist组件
<template>
  <div class="list">
    <van-pull-refresh v-model="isLoading" @refresh="onRefresh">
       <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
         <div class="list_content" v-for="pro in prolists" :key="pro.proid" @click="todetail(pro.proid)">
          <div class="list_img">
              <img :src="pro.proimg" alt="">
          </div>
          <div class="list_del center">
              <ul class="list_items">
                  <li>{{pro.proname}}</li>
                  <li>库存:{{pro.sales}}</li>
                  <li style="color: red"><span style="color: black">¥:</span>{{pro.price}}</li>
              </ul>
          </div>
        </div>
       </van-list>
    </van-pull-refresh>
  </div>
</template>

<script>
import Vue from 'vue'
import { PullRefresh, Toast, List } from 'vant'
import request from '../../api/index'
Vue.use(PullRefresh)
Vue.use(List)
export default {
  data () {
    return {
      prolists: '',
      pageCode: 1,
      isLoading: false,
      loading: false,
      finished: false
    }
  },
  created: function () {
    request({
      method: 'get',
      url: '/pro'
    }).then(res => {
      this.prolists = res.data.data
    })
  },
  methods: {
    onRefresh () { // 下拉刷新
      request.get('pro', {
        params: {
          pageCode: 1
        }
      }).then(res => {
        this.isLoading = false
        this.prolists = res.data.data
        Toast('刷新成功')
        console.log(this.prolists)
      })
    },
    todetail (proid) {
      this.$router.push('/detail/' + proid) // 路由传参跳转
    },
    onLoad () { // 上拉加载
      this.loading = true
      request.get('pro', {
        params: {
          pageCode: this.pageCode
        }
      }).then(res => {
        this.loading = false
        this.pageCode++
        if (res.data.code === '10000') {
          this.finished = true
        } else {
          this.prolists = [...this.prolists, ...res.data.data]
        }
      })
    }
  }
}
</script>

<style  scoped>
    .list {
        padding-bottom: 40px;
    }
    .center {
        display: flex;
        align-items: center;
    }
    .list_content {
        display: flex;
        padding: 1rem;
    }
    .list_img {
        padding: 0rem 1.5rem 0rem 0rem;
    }
    .list_del {
        width: 100%;
    }
</style>>

动态路由传参

跳转页面

  <div class="list_content" v-for="pro in prolists" :key="pro.proid" @click="todetail(pro.proid)">
          <div class="list_img">
              <img :src="pro.proimg" alt="">
          </div>
          <div class="list_del center">
              <ul class="list_items">
                  <li>{{pro.proname}}</li>
                  <li>库存:{{pro.sales}}</li>
                  <li style="color: red"><span style="color: black">¥:</span>{{pro.price}}</li>
              </ul>
          </div>
        </div>
//js部分
 todetail (proid) {
      this.$router.push('/detail/' + proid)//点击事件传递proid参数
    }

路由文件

  {
    path: '/detail/:proid',//动态绑定路由 注意!!!这里必须绑定(:proid)不然跳转到详情页刷新后就获取不到路由信息了
    name: 'detail',
    component: () => import('../views/detail/index.vue')
  }

被跳转页面(detail页面)

<script>
import request from '../../api/index'
export default {
  data () {
    return {
      proDetail: []
    }
  },
  mounted: function () {
    const { $route: { params: { proid } } } = this//this.$router.params获取路由参数proid 
    request({//使用proid字段请求数据
      method: 'GET',
      url: '/pro/detail',
      params: {
        proid
      }
    }).then(res => {
      this.proDetail = res.data.data
    })
  }
}
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值