Vue2.5开发去哪网App项目实战记录(根据慕课网课程编写)

慕课网课程链接
目的:只是为了记录自己学习过程中遇到的问题以及整个项目的收获,方便回头复习,以及今后编写项目的一个教程规范,文中基础知识并没有详细介绍,但是附上了相关的学习链接

首先先说下这个项目涉及到的知识点,以及整个开发过程的流程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
整个项目中数据的请求主要涉及到Axios,页面路由的控制主要由Vue-Router来实现,另外页面的样式编写是依赖了Stylus,整个项目的主要思想是组件化开发,其中包含页面上的单独组件,公用的组件,以及还讲到了递归组件的使用,涉及到组件的调用可以异步使用,另外还运用到了多个插件,比如vue-awesome-swiper实现了轮播图的效果,better-scroll主要实现了城市列表滑动的需求等

一、Vue基础知识
这部分知识官方API上讲解的非常详细(并且包含视频讲解,非常有心):https://cn.vuejs.org/v2/guide/index.html添加链接描述
在这里插入图片描述
其中需要注意的是:

  1. 组件,涉及到了注册,props传值(父向子传值),以及$emit(子向父传值),另外插槽的使用需要仔细看看,异步组件主要运用到路由中比较多,component: () => import(’@/pages/home/Home’),为了异步加载路由
  2. 动画:主要是transition的应用

比如图片的进入以及消失的渐隐渐现的效果实现

FadeAnimation.Vue: transition 包裹

.<template>
    <div>
        <transition>
            <slot></slot>
        </transition>
    </div>
</template>

<script>
export default {
    name:'FadeAnimation'
}
</script>

<style lang="stylus" scoped>
    .v-enter,v-leave-to
        opacity: 0
    .v-enter-active, .v-leave-active
        transition: opacity .5s
</style>

具体使用的时候,只需要fade-animation将需要用到动画的对象包裹起来即可

<fade-animation>
      <gallery
        :imgs="imgs" 
        v-show="showGallery"
        @close-gallery="handleCloseGallery">
      </gallery>
    </fade-animation>

二、Vue-Router的使用
以下为router的基本使用,详细router学习,请点击学习Vue-router官方文档

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: () => import('@/pages/home/Home')
    },
    {
      path: '/city',
      name: 'City',
      component: () => import('@/pages/city/City')
    },
    {
      path: '/detail/:id',
      name: 'Detail',
      component: () => import('@/pages/detail/Detail')
    }
  ],
  scrollBehavior: () => ({
    x:0,
		y: 0
	}),
})

HTML使用

<router-link to="/city"></router-link>  

JS

//类似于get请求,将参数拼接到url上,path是路由中path值
this.$router.push({
	path: '/cabinMaintain',
	query: {
		airlinesNumber: airlinesNumber
	}
})
//类似于post请求,name是路由中的name值
this.$router.push({
	name: 'CabinMaintain',
	params: {
		airlinesNumber: airlinesNumber
	}
})

获取

this.$route.query.airlinesNumber
this.$route.params.airlinesNumber

注意:
component: () => import(’@/pages/home/Home’)异步加载,目的是点击哪个页面,才开始加载该页面,而 不是在首页加载渲染好所有的页面

path: ‘/detail/:id’,动态路由,根据id不同,区分不同的路由页

三、Vuex状态管理,见另一篇文章Vuex 状态管理以及Vuex官方API

四、axios的使用,ajax请求axios官方文档
npm

npm install axios

项目中具体使用

main.js

import axios from 'axios'

Vue.prototype.$http = axios

login.js

import request from '@/utils/request'

export function login(type, params) {
	return request({
		url: '/login',
		method: 'post',
		params
	})
}

request.js

import axios from 'axios'
const service = axios.create({
  baseURL: process.env.BASE_API, // api 的 base_url
  timeout: 180000 ,// 请求超时时间
  withCredentials: true, // 允许携带cookie
})

service.interceptors.request.use(
	config => {
		return config
	},
	error => {
		Promise.reject(error)
	}
)

service.interceptors.response.use(
	response => {
		return response
	},
	error => {
		return Promise.reject(error)
	}
)

export default service

config/dev.env.js

'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  BASE_API: '"http://10.197.72.62:8888"'
})

五、插件以及依赖的使用

  1. 轮播图:vue-awesome-swiper : vue-awesome-swiper

npm

npm install vue-awesome-swiper --save

mount (main.js中)

import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'

// require styles
import 'swiper/dist/css/swiper.css'

Vue.use(VueAwesomeSwiper, /* { default global options } */)

具体使用swiper.vue

<template>
  <div class="wrapper">
    <swiper :options="swiperOption" v-if="showSwiper">
      <!-- slides -->
      <swiper-slide class="swiper-img"  v-for="item in swiperList" :key="item.id">
        <img :src="item.imgUrl" />
      </swiper-slide>
      <!-- Optional controls -->
      <div class="swiper-pagination" slot="pagination"></div>
    </swiper>
  </div>
</template>

<script>
export default {
  name: "HomeSwiper",
  props:{
    swiperList:{
      type:Array,
      default:[]
    }
  },
  data () {
    return {
      swiperOption: {
        pagination: {
          el: ".swiper-pagination"
        },
        loop:true
      },
    };
  },
  computed: {
    showSwiper () {
      return this.swiperList.length
    }
  }
};
</script>

<style lang="stylus" scoped>
.wrapper >>> .swiper-pagination-bullet-active {
  background: #fff;
} 

</style>
  1. better-scroll : 解决移动端的滚动情况,iscoll的封装。better-scroll

npm

npm install better-scroll --save

使用:(list.vue具体列表页面)

import BScroll from "better-scroll";

mounted() {
    this.scroll = new BScroll(this.$refs.wrapper);
  },
  1. fastclick:
    移动设备上的浏览器默认会在用户点击屏幕大约延迟300毫秒后才会触发点击事件,这是为了检查用户是否在做双击。为了能够立即响应用户的点击事件,才有了FastClick。
npm install better-scroll --save
  1. babel-polyfill :
    为了解决ie9和一些低版本的高级浏览器对es6新语法并不支持,而出现白屏的情况
npm install babel-polyfill --save
  1. stylus:
    Stylus是一个CSS预处理器为您详细比较三个 CSS 预处理器(框架):Sass、LESS 和 Stylus

六、移动端注意事项
1.index.html

< meta name=“viewport” content=“width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no”>
手机端不需要放缩

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <title>travel</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

2.main.js

import 'styles/reset.css'
import 'styles/border.css'

reset.css是手机的适配,border.css是为了解决手机端一像素问题
reset.css

@charset "utf-8";html{background-color:#fff;color:#000;font-size:12px}
body,ul,ol,dl,dd,h1,h2,h3,h4,h5,h6,figure,form,fieldset,legend,input,textarea,button,p,blockquote,th,td,pre,xmp{margin:0;padding:0}
body,input,textarea,button,select,pre,xmp,tt,code,kbd,samp{line-height:1.5;font-family:tahoma,arial,"Hiragino Sans GB",simsun,sans-serif}
h1,h2,h3,h4,h5,h6,small,big,input,textarea,button,select{font-size:100%}
h1,h2,h3,h4,h5,h6{font-family:tahoma,arial,"Hiragino Sans GB","微软雅黑",simsun,sans-serif}
h1,h2,h3,h4,h5,h6,b,strong{font-weight:normal}
address,cite,dfn,em,i,optgroup,var{font-style:normal}
table{border-collapse:collapse;border-spacing:0;text-align:left}
caption,th{text-align:inherit}
ul,ol,menu{list-style:none}
fieldset,img{border:0}
img,object,input,textarea,button,select{vertical-align:middle}
article,aside,footer,header,section,nav,figure,figcaption,hgroup,details,menu{display:block}
audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
blockquote:before,blockquote:after,q:before,q:after{content:"\0020"}
textarea{overflow:auto;resize:vertical}
input,textarea,button,select,a{outline:0 none;border: none;}
button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
mark{background-color:transparent}
a,ins,s,u,del{text-decoration:none}
sup,sub{vertical-align:baseline}
html {overflow-x: hidden;height: 100%;font-size: 50px;-webkit-tap-highlight-color: transparent;}
body {font-family: Arial, "Microsoft Yahei", "Helvetica Neue", Helvetica, sans-serif;color: #333;font-size: .28em;line-height: 1;-webkit-text-size-adjust: none;}
hr {height: .02rem;margin: .1rem 0;border: medium none;border-top: .02rem solid #cacaca;}
a {color: #25a4bb;text-decoration: none;}

border.css

@charset "utf-8";
.border,
.border-top,
.border-right,
.border-bottom,
.border-left,
.border-topbottom,
.border-rightleft,
.border-topleft,
.border-rightbottom,
.border-topright,
.border-bottomleft {
    position: relative;
}
.border::before,
.border-top::before,
.border-right::before,
.border-bottom::before,
.border-left::before,
.border-topbottom::before,
.border-topbottom::after,
.border-rightleft::before,
.border-rightleft::after,
.border-topleft::before,
.border-topleft::after,
.border-rightbottom::before,
.border-rightbottom::after,
.border-topright::before,
.border-topright::after,
.border-bottomleft::before,
.border-bottomleft::after {
    content: "\0020";
    overflow: hidden;
    position: absolute;
}
/* border
 * 因,边框是由伪元素区域遮盖在父级
 * 故,子级若有交互,需要对子级设置
 * 定位 及 z轴
 */
.border::before {
    box-sizing: border-box;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    border: 1px solid #eaeaea;
    transform-origin: 0 0;
}
.border-top::before,
.border-bottom::before,
.border-topbottom::before,
.border-topbottom::after,
.border-topleft::before,
.border-rightbottom::after,
.border-topright::before,
.border-bottomleft::before {
    left: 0;
    width: 100%;
    height: 1px;
}
.border-right::before,
.border-left::before,
.border-rightleft::before,
.border-rightleft::after,
.border-topleft::after,
.border-rightbottom::before,
.border-topright::after,
.border-bottomleft::after {
    top: 0;
    width: 1px;
    height: 100%;
}
.border-top::before,
.border-topbottom::before,
.border-topleft::before,
.border-topright::before {
    border-top: 1px solid #eaeaea;
    transform-origin: 0 0;
}
.border-right::before,
.border-rightbottom::before,
.border-rightleft::before,
.border-topright::after {
    border-right: 1px solid #eaeaea;
    transform-origin: 100% 0;
}
.border-bottom::before,
.border-topbottom::after,
.border-rightbottom::after,
.border-bottomleft::before {
    border-bottom: 1px solid #eaeaea;
    transform-origin: 0 100%;
}
.border-left::before,
.border-topleft::after,
.border-rightleft::after,
.border-bottomleft::after {
    border-left: 1px solid #eaeaea;
    transform-origin: 0 0;
}
.border-top::before,
.border-topbottom::before,
.border-topleft::before,
.border-topright::before {
    top: 0;
}
.border-right::before,
.border-rightleft::after,
.border-rightbottom::before,
.border-topright::after {
    right: 0;
}
.border-bottom::before,
.border-topbottom::after,
.border-rightbottom::after,
.border-bottomleft::after {
    bottom: 0;
}
.border-left::before,
.border-rightleft::before,
.border-topleft::after,
.border-bottomleft::before {
    left: 0;
}
@media (max--moz-device-pixel-ratio: 1.49), (-webkit-max-device-pixel-ratio: 1.49), (max-device-pixel-ratio: 1.49), (max-resolution: 143dpi), (max-resolution: 1.49dppx) {
    /* 默认值,无需重置 */
}
@media (min--moz-device-pixel-ratio: 1.5) and (max--moz-device-pixel-ratio: 2.49), (-webkit-min-device-pixel-ratio: 1.5) and (-webkit-max-device-pixel-ratio: 2.49), (min-device-pixel-ratio: 1.5) and (max-device-pixel-ratio: 2.49), (min-resolution: 144dpi) and (max-resolution: 239dpi), (min-resolution: 1.5dppx) and (max-resolution: 2.49dppx) {
    .border::before {
        width: 200%;
        height: 200%;
        transform: scale(.5);
    }
    .border-top::before,
    .border-bottom::before,
    .border-topbottom::before,
    .border-topbottom::after,
    .border-topleft::before,
    .border-rightbottom::after,
    .border-topright::before,
    .border-bottomleft::before {
        transform: scaleY(.5);
    }
    .border-right::before,
    .border-left::before,
    .border-rightleft::before,
    .border-rightleft::after,
    .border-topleft::after,
    .border-rightbottom::before,
    .border-topright::after,
    .border-bottomleft::after {
        transform: scaleX(.5);
    }
}
@media (min--moz-device-pixel-ratio: 2.5), (-webkit-min-device-pixel-ratio: 2.5), (min-device-pixel-ratio: 2.5), (min-resolution: 240dpi), (min-resolution: 2.5dppx) {
    .border::before {
        width: 300%;
        height: 300%;
        transform: scale(.33333);
    }
    .border-top::before,
    .border-bottom::before,
    .border-topbottom::before,
    .border-topbottom::after,
    .border-topleft::before,
    .border-rightbottom::after,
    .border-topright::before,
    .border-bottomleft::before {
        transform: scaleY(.33333);
    }
    .border-right::before,
    .border-left::before,
    .border-rightleft::before,
    .border-rightleft::after,
    .border-topleft::after,
    .border-rightbottom::before,
    .border-topright::after,
    .border-bottomleft::after {
        transform: scaleX(.33333);
    }
}

6.手机端手势touchstart监听有问题,页面会跟着拖拽,而不是列表滑动,需要touchstart.prevent,prevent修饰符阻止默认程序

整个项目路径:

http:https://gitee.com/JiuYueShang/Travel
SSH:[email protected]:JiuYueShang/Travel.git

发布了62 篇原创文章 · 获赞 33 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/Silence_Sep/article/details/102580427