文章目录
功能:
首页、分类、购物车、我的
上传码云
git remote add origin https://gitee.com/lkp_ksbk/ionic_jd_shop.git
git push -u origin master
搭建项目,增加tab4,并修改tab样式
ionic start jdshop tabs // 搭建项目
ionic g page tab4 // 第四个tab页面
添加上tab4,然后修改tab的文字和icon。
首页:home、分类:shirt、购物车: cart、 我的:settings
修改tab的颜色:
1.使用自定义主题色的方法,并没有改变tab的选中颜色,所以不行。
2.修改某一类组件的颜色(ion-tab-button
)。css properties
.ion-color-tabs {
--ion-color-base: #69bb7b;
--ion-color-base-rgb: 105,187,123;
--ion-color-contrast: #ffffff;
--ion-color-contrast-rgb: 255,255,255;
--ion-color-shade: #5ca56c;
--ion-color-tint: #78c288;
}
// 可以把base和contrast的颜色做一个调换,那么背景是白色的,只是选中和非选中只有一点色差,不是那种选中红,不选中黑的状态。
// 修改底部图标的选中颜色以及默认颜色
ion-tab-button{
--color:#8C8E8C;
--color-selected:#F53D3D;
}
android和ios配置统一样式
默认:android和ios是两套不一样的样式。
app.module.ts:
IonicModule.forRoot() // forRoot可以配置参数。
可以配置很多,自己进去看看,eg:backButtonIcon,animated,menuIcon,menuType等等。
IonicModule.forRoot({
mode:'ios', // 都是ios样式
backButtonText:'返回' // 返回按钮,默认是汉字,不是back了。
}),
添加全局样式和rem
global.scss和variables.scss中都行。
/*自定义的全局css样式*/
body,
div,
ul,
li,
ol,
h1,
h2,
h3,
h4,
h5,
h6,
input,
textarea,
select,
p,
dl,
dt,
dd,
a,
img,
button,
form,
table,
th,
tr,
td,
tbody,
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
margin: 0;
padding: 0;
}
html {
font-size: 62.5%; // 浏览器的默认字体大小是16px 16*62.5%=10px
}
.clearfix {
&::after {
display: block;
content: "";
height: 0px;
clear: both;
}
}
ul,
ol {
list-style-type: none;
}
search模块布局
第三方字体图标icon
eg:iconfont
选中icon下载,然后选择颜色和大小及格式,即可。eg:下载png格式,我们就可以使用iconfont的图标了。
search:扫码和消息icon。
search:i-searchbar
消息提示icon:i-badge。
<ion-header [translucent]="true">
<ion-toolbar>
<!-- 左侧的扫码icon -->
<ion-buttons slot="start" class="qrcode-container">
<ion-img src="assets/images/qrcode.png"></ion-img>
</ion-buttons>
<!-- 搜索框 -->
<!-- (ionChange)="onSearchChange($event)" -->
<ion-searchbar placeholder="请输入搜索内容" [debounce]="250" animated>
</ion-searchbar>
<!-- 右侧的消息icon -->
<ion-buttons slot="end" class="message-container">
<ion-img src="assets/images/message.png"></ion-img>
<ion-badge color="danger" mode="ios" class="message-badge">9</ion-badge>
</ion-buttons>
</ion-toolbar>
</ion-header>
// badge需要定位一下,且container需要给一个padding,那么就能对齐了。
轮播图
图片:
/**
* 轮播图 第一次滑动轮播图的时候,会有一个白色背景的问题,应该是图片不知道h,所以触发的
*/
public slidesList = [];
getSlidesList() {
for (let i = 1; i < 4; i++) {
this.slidesList.push({
pic: `assets/images/slide0${i}.png`, // 图片
url: '' // 跳转的地址
});
}
}
轮播图配置:
1.配置参数,自动轮播
2.手动操作后,需要继续自动轮播。
//轮播图的属性
public slidesOpts={
speed:400,
autoplay: {
delay: 2000,
},
loop:true,
effect: 'slide' // 'slide'(普通切换、默认),"fade"(淡入)"cube"(方块)"coverflow"(3d流)"flip"(3d翻转)
}
问题:
1.N张图片,第一次循环轮播的时候,每个图片会闪一下空白(跟没找到图片高度似的,第一次循环之后就ok了)
2.设置loop后自动轮播,循环过程中,再到第一张图片的时候,页面会空白,不显示第一张图片。
解决:
<!-- 轮播图 -->
<!-- ion-slide中不要使用ion-img,直接使用img即可,就不会出现上面的问题。-->
<ion-slides #homeSlides pager='true' [options]="slidesOpts" (ionSlideTouchEnd)="doSlideChange()">
<ion-slide *ngFor="let item of slidesList">
<img [src]="item.pic" />
</ion-slide>
</ion-slides>
(ionSlideTouchEnd)="slideTouchEnd()"
//手动滑动完成
slideTouchEnd(){
this.slide1.startAutoplay();
}
ion-slide{
ion-slides {
height: 15rem;
ion-slide {
width: 100%;
height: 100%;
overflow: hidden;
img{
width: 100%;
height: 100%;
}
}
}
pager
:是否显示分页。
猜你喜欢(可滑动的推荐商品列表)
for(var i=1;i<=7;i++){
this.hotList.push({
pic:'assets/0'+i+'.jpg',
title:'第'+i+'个',
})
}
//计算hotListWidth的宽度
this.hotListWidth=this.hotList.length*9+'rem';
思路:外层盒子w100%,里层的ul要设置宽一些(计算准确的宽),然后外层overflow:auto即可。
<!-- 外层盒子 -->
<div class="content">
<!-- 内层盒子 -->
<ul class="recommend-list-ul">
<li *ngFor="let item of recommendList">
<img [src]="item.pic" alt="" />
</li>
</ul>
</div>
// 外层
.content {
overflow-x: auto;
// 内层
.recommend-list-ul {
width: 90rem; // 每一个img是10rem,一共9张图(计算获取)
li {
float: left;
img {
width: 9rem;
margin: 0.5rem;
}
}
}
}
<ul class="recommend-list-ul" [ngStyle]="{'width':10*this.recommendList.length+'rem'}">
商品列表
栅格布局:
<ion-grid fixed>
<ion-row>
<ion-col size="6" *ngFor="let item of productList">
<img [src]="item.pic" alt="" />
<div class="img-desc">{{item.title}}</div>
</ion-col>
</ion-row>
</ion-grid>
商品分类
左、右侧布局:display:flex;布局。
同时要左右两侧各自滚动,不影响其他:同home-可滑动的推荐商品列表(内层1000px,外层100px,overflow:auto;)
购物车页面
1.购物车商品的页面布局
2.底部的全选和结算
用户中心
头部用户信息
div使用flex布局即可。
用户信息列表
i-item-icon
背景图片(/assets
开头):
background: url('/assets/images/user_bg.jpg') no-repeat center center;
html中:
可以/
开头,也可以不。
ionic项目的真机调试:
1.ionic serve的时候,根据ip地址打开。
公司网络不支持?
mac查ip:设置>网络>高级>TCP/IP>IPv4地址。
电脑联手机演示
360手机助手(手机演示)
问题:
1.轮播图没有铺满,所以有问题;(w100%即可)
2.fontsize:62.5%,所以没有设置fz的时候,都是12*62.5=10px;浏览器最小12所以觉得没问题,但是手机上就不行了。
// global.css中设置:
body {
font-size: 1.4rem;
}
点击search调到search页面(共用的)
tap事件为什么又不可用了?需要安装hammer.js??我写成click事件了…
安装了hammer也不能使用tap?
constructor(
public router: Router,
public navCtrl: NavController
) {}
// 使用Router跳转
// this.router.navigate(['/search']);
// 使用NavController跳转
this.navCtrl.navigateForward('/search');
search的详情页面
点击返回的时候,返回首页或者分类页面,说明:
search详情页面不是一个单独的页面,跟search是同一个页面。
固定的二级导航
header中再来一个i-toolbar即可。固定在头部的。
修改组件的默认样式:
// 二级导航
ion-toolbar.sub_header{
display: flex; // 没有display的属性,所以不能修改;如果想修改,包一层div
background: red; // 不起作用
--background:red; // 正确的修改组件样式
.sub_title{
flex:1;
}
}
i-item默认一行就…显示了,有时候不需要这样式。
登录页面
toobar下面的底边线要去掉;
toolbar有border-color属性,没有border属性;我们修改border-color颜色即可。
忘记密码和用户注册布局:可以使用flex左右布局,也可以直接使用slot
的方法。
<ion-list>
<ion-item lines="none">
<span slot="start">忘记密码</span>
<span slot="end">用户注册</span>
</ion-item>
</ion-list>
注册页面
功能(三个独立的页面):输入手机号,发送验证码,输入密码。
NavController:back
,navigateBack
,navigateForward
,navigateRoot
,
input框:
原生input是行内元素;
ion-input是块级元素;padding-left:0;
ion-input {
border: 1px solid #ccc;
width: 80%;
height: 3.2rem;
margin: 2rem auto; // 块级元素
--padding-start: .6rem; // 给一个左padding
}
ion-item有默认的样式,需要自己调整一下才能左右对齐
--padding-start
--padding-end
封装接口
接口地址:https://www.itying.com/article-11.html
轮播图:http://jd.itying.com/api/focus
猜你推荐:http://jd.itying.com/api/plist?is_hot=1&pageSize=20&page=1
热门推荐:http://jd.itying.com/api/plist?is_best=1&pageSize=20&page=1
ionic g service services/http
HttpClientModule
和HttpClient
调用接口,渲染数据。
商品分类接口联调
一级分类(左侧): http://jd.itying.com/api/pcate
二级分类(右侧): http://jd.itying.com/api/pcate?pid=59f1e1ada1da8b15d42234e9
商品分类-第三分类页面
第三分类:http://jd.itying.com/api/plist
参数:
cid:第二分类的id。
search:模糊搜索的内容。
page:page
pageSize:size
sort:排序; 综合:all,销量:sales,价格:price
1.价格:sort=price_1 或者 sort=price_-1
2.销量:salecount_1salecount_-1
3.综合:all
功能:
1.上拉加载更多
2.下拉刷新
3.排序
商品分类-第三分类页面-排序
问题:
1.切换tab的时候,页面没有滚动到最顶部
2.加入tab1滚动到最底部,已经禁用上拉加载更多了,切换到tab2的时候,需要放开该功能。
3.升序和降序都要做。(功能已经实现,可以加上向上或者向下的箭头,完成页面)
// 获取ion-content,让它滚动到顶部
@ViewChild(IonContent) ionContent: IonContent;
// 也可以给ion-content用id,用id的方式获取(dom操作:#productListContent)
this.ionContent.scrollToTop(0); /*回到顶部*/
@ViewChild('productListScroll') productListScroll: any;
this.productListScroll.disabled = false; // 恢复上拉加载更多功能
// 升序和降序:每次点击后,改变sort的值,那么再次点击就已经改变了。
this.navList[id - 1].sort = this.navList[id - 1].sort * -1; // 升序和降序:改变sort的值。
注:在做箭头排序的时候,title的样式(颜色)影响了内部icon的颜色,所以一直在做上下判断的时候,不起作用。
.sub_title.active {
background: #eee;
span {
color: #f40; // 只给title加样式;icon自己单独加
}
// color: #f40; // 会影响到箭头的颜色
}
search页面同样的问题
1.清空list
2.重置page
3.滚动到顶部
4.放开infinite-scroll的限制。
历史记录
storageService:
ionic g service services/storage
添加历史记录
删除历史记录
商品详情
注册页面
1.封装了post的请求。
2.发送验证码
3.倒计时
4.验证验证码
5.注册
登录功能
1.登录功能
2.订阅
3.生命周期
ngOnInit只有刷新的时候执行了一次,来回切换tab的时候,这个生命周期函数不执行了!!!
为什么???
如果切换tab每次都执行生命周期函数的话,那么会一直调用接口,不太好,所以有缓存的。
所以,不用angualr的生命周期函数,用ionic的生命周期函数。
生命周期函数:
// enter:在tab切换或者第一此执行会触发,在login页面返回没有触发:
// leave:在login页面返回时触发了
ionViewWillEnter:当进入一个页面时触发(如果它从堆栈返回)
ionViewDidEnter:进入后触发
ionViewWillLeave:如果页面将离开触发
ionViewDidLeave:在页面离开后触发
ionViewWillUnload:页面卸载的时候会触发,如果无法触发使用 ngOnDestroy
注:tab4切换到login页面的时候,tab4没有卸载掉,只是push了login页面进去,所以返回的时候,没有执行enter的事件。为了运行速度。
EventEmitter
- npm搜索,发现:
eventemitter
很少下载量,eventemitter3
下载很多,说明现在用eventemitter3
的比较多。 - github:https://github.com/primus/eventemitter3
使用:
// 安装配置 EventEmitter
npm install --save eventemitter3
ionic g service services/event
// src/app/services/event.service.ts
import { Injectable } from '@angular/core';
import { EventEmitter } from 'eventemitter3';
@Injectable({
providedIn: 'root'
})
export class EventService {
public eventEmit: any;
constructor() {
// 定义发射事件
// 这个实例,被多个组件共享,来实现数据在不同页面之间的共享
this.eventEmit = new EventEmitter();
}
}
// 登录页面发出广播:
this.envetService.eventEmit.emit('userInfo', '登录了吗?哈哈' );
// 接收页面接收广播 on默认不触发,只有发出广播后,才会触发。
// 监听事件 eventEmit:是自定义的名字。
this.eventService.eventEmit.on('userInfo', params => {
console.log('tab4-订阅事件的params:', params);
});
账号密码:
注册的时候,验证码在后端接口有返回。
已注册密码:
123/123
admin/admin
root/root
设置页面
ionic g page personal
- 更改用户信息:生日、性别等
- 退出登录
清空storage,然后发布广播,回到setting页面。
slot的使用,可以自动放在末尾:
<ion-list lines='full'>
<ion-item>
头像
<span slot='end' class="item_note">
<img [src]="personalInfo.avatar" class="avatar" alt="">
</span>
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
</ion-item>
</ion-list>
添加到购物车功能
属性选择
- 课程里的方法:js原生方法:事件委托:
/**
* 选择属性
*/
changeAttr(e) {
console.log('事件对象e:', e);
console.log('事件对象e.srcElement:', e.srcElement);
console.log('事件对象e.srcElement.nodeName:',e.srcElement.nodeName); // SPAN 大写标签名
console.log('事件对象e.srcElement.className:',e.srcElement.className); // attr_cont
if (e.srcElement.className.indexOf('attr_cont') > -1) {
console.log('点击了某一条attr');
const ele = e.srcElement; // 获取当前dom节点
// 获取父节点
const parentEle = ele.parentNode;
// 所有子节点
const childrenEle = parentEle.children;
console.log('所有子节点:', childrenEle);
// childrenEle.forEach((v,k)=>{
// v.removeClassName('active');
// })
// 所有节点去掉active的类名
for (let i = 0;i < childrenEle.length;i++) {
console.log( '每个子节点的className:', childrenEle[i].className );
childrenEle[i].className = childrenEle[i].className.replace('active', '');
}
// 当前元素增加class:active
ele.className = ele.className + ' active';
}
}
- 使用angular方法
<!-- 第一层循环 -->
<div class="attr_item" *ngFor="let item of productDetail.attr">
<span class="attr_title">{{item.cate}}:</span>
<!-- 第二层循环 -->
<span class="attr_cont" *ngFor="let item2 of item.list"
(click)="selectAttr(item,item2)"
[ngClass]="{'active': item.selectedAttr == item2}">{{item2}}</span>
</div>
/**
* 切换属性
* @param item :第一层循环的item
* @param item2 :第二层循环的item
*/
selectAttr(item,item2){
item.selectedAttr = item2;
}
数量选择
添加到购物车
-
存储数据:接口或者storage存储在本地;
本地的话,判断是否有重复的,需要计算。