目录
产品预览
准备工作
项目开始
页面结构和根组件 app.vue
编写底部导航栏
编写路由
编写Home页面
顶部标题栏
轮播图
src目录下创建项目
1、引入assets下的字体文件,然后配置scss。(_variables.scss、_mixins.scss、_reset.scss、_icons.scss、_base.scss、index.scss 加入下划线是为了不被编译为css,统一在index中引入 )
//引入 main.js
import 'assets/scss/index.scss';
2、配置mian.js 引入index.scss完成基础配置。sass引入无法识别、需要引入两个插件sass-loader、node-sass
cnpm install [email protected] --save-dev
cnpm install --save-dev node-sass
3、安装一些包 babel-polyfill fastclick、 然后在mian.js引入
安装
cnpm install --save-dev babel-polyfill
cnpm install --save-dev fastclick
引入 main.js
import 'babel-polyfill'
import fastclick from 'fastclick'
fastclick.attach(document.body);
4、路由下的@符号是别名的意思,我们可以去build下的webpack.base.conf.js文件去修改。修改后路由下就可以用别名作为路径。
//原来别名
alias: {
'@': resolve('src'),
'abc': resolve('src'),
}
//修改后
alias: {
'api': resolve('src/api'),
'assets': resolve('src/assets'),
'base': resolve('src/base'),
'components': resolve('src/components'),
'pages': resolve('src/pages')
}
/*_container.scss*/
@import "mixins";
.g-container {
overflow: hidden;
position: relative;
width: 100%;
max-width: 640px;
min-width: 320px;
height: 100%;
margin: 0 auto;
}
.g-view-container {
height: 100%;
padding-bottom: $tabbar-height;
}
.g-content-container {
height: 100%;
padding-top: $navbar-height;
}
.g-header-container {
position: absolute;
left: 0;
top: 0;
z-index: $navbar-z-index;
width: 100%;
}
.g-footer-container {
position: absolute;
left: 0;
bottom: 0;
z-index: $tabbar-z-index;
width: 100%;
box-shadow: 0 0 10px 0 hsla(0, 6%, 58%, 0.6);
}
.g-backtop-container {
position: absolute;
z-index: $backtop-z-index;
right: 10px;
bottom: $tabbar-height + 10px;
}
如果想要保持占满全屏 不溢出需要全局设置body和html 宽高、溢出隐藏
html, body {
overflow: hidden;
width: 100%;
height: 100%;
}
//app.vue 界面引入自定义底部导航组件
//commponents下tabber index.vue
/*_tabber.scss */
@import "mixins";
.g-tabbar {
display: flex;
width: 100%;
height: $tabbar-height;
background-color: #fff;
&-item {
flex: 1;
@include flex-center(column);
.iconfont {
margin-bottom: 4px;
font-size: $icon-font-size;
}
}
}
//_mixins
@import "variables";
// flex-center
@mixin flex-center($direction: row) {
display: flex;
justify-content: center;
align-items: center;
flex-direction: $direction;
}
效果
创建页面并配置路由,home、product、category、cart、personal、seach
注意:*通配符 如果上面没有匹配到就导航到home、() => import('pages/home')路由懒加载,只在显示是加载页面信息。
//router配置
import Vue from 'vue'
import Router from 'vue-router'
// import Home from 'pages/home'
// import Category from 'pages/category'
// import Cart from 'pages/cart'
// import Personal from 'pages/personal'
// import Product from 'pages/product'
// import Search from 'pages/search'
Vue.use(Router)
const routes = [
{
name: 'home',
path: '/home',
component: () => import('pages/home'),
children: [
{
name: 'home-product',
path: 'product/:id',
component: () => import('pages/product')
}
]
},
{
name: 'category',
path: '/category',
component: () => import('pages/category')
},
{
name: 'cart',
path: '/cart',
component: () => import('pages/cart')
},
{
name: 'personal',
path: '/personal',
component: () => import('pages/personal')
},
{
name: 'search',
path: '/search',
component: () => import('pages/search')
},
{
path: '*',
redirect: '/home'
}
]
export default new Router({
routes
})
//home下 index.vue
//home下 header.vue
搜索框
//base下navbar
安装vue-awesome-swiper
cnpm install --save-dev [email protected]
//main.js 全局引入css
import 'swiper/dist/css/swiper.css'
//home 下 index.vue
//header.vue
搜索框
//base下创建 slider 下创建index.vue
//config.js
export const sliderOptions = {
direction: 'horizontal',
loop: true,
interval: 0,
pagination: true,
}
安装axios插件,
cnpm install --save-dev axios
//home 下的 index.vue
//api下的 home.js
import axios from 'axios';
import { SUCC_CODE, TIMEOUT } from './config';
// 获取幻灯片数据 -- ajax
export const getHomeSlider = () => {
return axios.get('http://www.imooc.com/api/home/slider', {
//这里是为了延迟10s 让网络超时 执行catch
// timeout: TIMEOUT
}).then(res => {
console.log(res)
if(res.data.code === SUCC_CODE){
return res.data.slider
}
throw new Error('没有成功获取到数据!')
}).catch(err => {
if (err){
console.log(err);
}
return [
{
linkUrl: 'https://www.imooc.com',
picUrl: require('assets/img/404.png')
}
]
}).then(data => {
// 这里是延迟1s返回 为了加 正在加载效果
return new Promise(resolve => {
setTimeout(() => {
resolve(data);
}, 1000);
});
})
};
//api 下的 config.js
export const SUCC_CODE = 0
export const TIMEOUT = 10000;
//home 下 slider.vue 引入正在加载组件并根据轮播图是否有数据显示
//base下 slider组件 实现正在加载
{{text}}
//home内引入 scroll组件
//scroll组件
在home引入 nav.vue
//nav.vue
//config.js
export const sliderOptions = {
direction: 'horizontal',
loop: true,
interval: 0,
pagination: true,
}
export const navItems = [
// 原nav.uve的数据
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-1.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-2.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-3.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-4.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-5.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-6.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-7.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-8.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-9.png'),
text: '拍卖'
},
{
linkUrl: 'https://www.imooc.com',
picUrl: require('./img/nav-item-10.png'),
text: '拍卖'
}
];
安装jsonp、安装vue-lazyload
cnpm install --save-dev jsonp
cnpm install vue-lazyload --save-dev
main.js引入
import VueLazyload from 'vue-lazyload';
Vue.use(VueLazyload, {
preLoad: 1,
error: require('assets/img/error.png'),
loading: require('assets/img/loading.gif'),
attempt: 1
});
//home下index.vue 注意:对组件封装 并且数据加载完成后注意刷新
//home下recommend 封装热卖商品组件
热卖推荐
-
{{item.name.shortName}}
¥{{item.price.origPrice}}
¥{{item.price.actPrice}}
{{item.remind.soldCount}}件已售
//base下 封装scroll组件
//base下loading组件
{{text}}
jsonp请求
//api下封装 home.js 请求jsonp
import axios from 'axios';
import jsonp from 'assets/js/jsonp';
import {SUCC_CODE, TIMEOUT, HOME_RECOMMEND_PAGE_SIZE, jsonpOptions} from './config';
// 获取幻灯片数据 -- ajax
export const getHomeSlider = () => {
return axios.get('http://www.imooc.com/api/home/slider', {
//这里是为了延迟10s 让网络超时 执行catch
// timeout: TIMEOUT
}).then(res => {
// console.log(res)
if(res.data.code === SUCC_CODE){
return res.data.slider
}
throw new Error('没有成功获取到数据!')
}).catch(err => {
if (err){
console.log(err);
}
return [
{
linkUrl: 'https://www.imooc.com',
picUrl: require('assets/img/404.png')
}
]
}).then(data => {
// 这里是延迟1s返回 为了加 正在加载效果
return new Promise(resolve => {
setTimeout(() => {
resolve(data);
}, 1000);
});
})
};
// 获取热门推荐数据--jsonp
export const getHomeRecommend = (page = 1, psize = HOME_RECOMMEND_PAGE_SIZE) => {
const url = 'https://ju.taobao.com/json/tg/ajaxGetItemsV2.json';
const params = {
page,
psize,
type: 0,
frontCatId: ''
};
return jsonp(url, params, jsonpOptions).then(res => {
console.log('jsonp', res);
if (res.code === '200') {
return res;
}
throw new Error('没有成功获取到数据!');
}).catch(err => {
if (err) {
console.log(err);
}
}).then(res => {
return new Promise(resolve => {
setTimeout(() => {
resolve(res);
}, 1000);
});
});
};
//home下 config.js
export const SUCC_CODE = 0;
export const TIMEOUT = 10000;
export const HOME_RECOMMEND_PAGE_SIZE = 20;
export const jsonpOptions = {
param: 'callback',
timeout: TIMEOUT
};
封装基本jsonp
//assets 下面 js jsonp.js 封装基本jsonp
import jsonp from 'jsonp';
const parseParam = param => {
let params = [];
for (const key in param) {
params.push([key, encodeURIComponent(param[key])]);
}
// [[page, 1], [pszie, 20]]
return params.map(value => value.join('=')).join('&');
// [[page, 1], [pszie, 20]]
// [page=1, psize=20]
// page=1&psize=20
};
export default (url, data, options) => {
url += (url.indexOf('?') < 0 ? '?' : '&') + parseParam(data)
// jsonp(url, opti)
return new Promise((resolve, reject) => {
jsonp(url, options, (err, data) => {
if(err) {
reject(err)
} else {
resolve(data)
}
});
})
}
下拉提示文字变化、松手刷新、刷新幻灯片。上拉加载更多。
注意:下拉刷新轮播图后需要更新轮播图,但是loop没有改变,拉到最后一页有bug。解决方法:查找重新加载api,但是官方未提供。那么我们采用给组件变换KEY来达到重新加载,这个是VUE特性。