0. 项目目录
- 欢迎页的实现
- 程序第一次运行实现
- 注册的实现
- 登陆的实现
- 首页的实现
- 店铺设置的实现
- 商品分类浏览的实现
- 编辑商品分类的实现
- 新增商品的实现
- 商品管理的实现
目录
# 写于2020.12.18
# 测试全部成功
# 测试内容包括:店铺名字更改,密码更改,对原始密码验证,关于我们页面跳转等
# 更新不易,望赞鼓励
1. 任务要求
1.1 店铺(系统)设置详细需求
用户场景:为了方便用户的使用,通过店铺(系统)设置页导航到相关的功能。用户在使用软件的过程遇到困难,可以通过店铺(系统)设置页面中的联系客服功能,拨打客服电话。
输出/后置条件:点击安全退出时,修改用户登录的状态,把已登录状态改为未登录状态。点击不同的列表项进
入相应的页面。
1.2. 查看店铺信息与修改店铺信息详细需求
用户场景:为了让用户快速注册,注册时填写的店铺信息较少。用户可以通过使用店铺(系统)设置中的查看
店铺信息和修改店铺信息功能,完善店铺的相关信息。
1.3 修改密码详细需求
2. 工作指导
- 参考之前的任务,创建店铺(系统)设置组件(含Module和Routing文件)。跟设置功能相关的页面都放在SettingPageModule中。在setting文件夹中分别创建AboutMe、ChangePassword、Shop等页面,最后在shop文件夹下创建edit(ShopEdit)页面。
- 在setting文件夹下创建SettingService,添加一个属性保存用户和店铺的相关信息,再添加一个属性保存应用程序相关信息。添加load方法,向服务器(本地存储)请求用户和店铺的相关数据,可以使用三点运算符把两个对象合并,并把得到的数据保存在本地存储中,登录成功时调用。
- 做到这里由于没有服务器,本地存储中保存了许多数据。部分数据代替了服务器数据库中的数据,另外一部分数据是客户端(浏览器端)需要保存的数据。
为了区分,用于代替服务器数据库存储的数据,Key前面+“T”,例如:TUser、TShop等。
3. 实现店铺(系统)设置页面
3.1 实现店铺(系统)设置的界面
使用3个ion-list。为每个ion-list元素添加inset属性,值设置为true,列表周围就会有边距和圆角。为
ion-item元素添加detail属性,在ion-item元素的右边显示右箭头图标。
src\app\pages\setting\setting.page.html
<ion-header>
<ion-toolbar>
<ion-button href='/home'>
<ion-icon name="arrow-back">返回</ion-icon>
</ion-button>
<ion-title>店铺设置</ion-title>
</ion-toolbar>
</ion-header>
<ion-content color="medium">
<ion-list inset="true">
<ion-item detail href="/setting/shop">
<ion-label>店铺设置</ion-label>
</ion-item>
<ion-item detail href="/setting/change-password">
<ion-label>密码</ion-label>
</ion-item>
</ion-list>
<ion-list inset="true">
<ion-item detail href="/setting/about-me">
<ion-label>关于我们</ion-label>
</ion-item>
<ion-item>
<ion-label>联系客服</ion-label>
<a href="tel:这里写你的电话号码">这里写你的电话号码</a>
</ion-item>
<ion-item detail href="">
<ion-label>版本号:1.0.0</ion-label>
<ion-note slot="end">检测更新</ion-note>
</ion-item>
</ion-list>
<ion-list inset="true">
<ion-item detail (click)="loginout()">
<ion-label>安全退出</ion-label>
</ion-item>
</ion-list>
<XXX-copyright [bottom]="'20px'"></XXX-copyright>
</ion-content>
detail属性,在item的右边显示一个向右的箭头图标。
ion-note是一种文本元素,通常用于副标题提供更多的信息。ion-note样式默认显示灰色。
- 自己的 copyRight替换
- 自己的电话号码替换一下
3.2 拨打电话联系客服
我用的前面这种方法
先在工程的根目录下找到config.xml文件,添加下面的配置:config.xml
<access origin="tel:*" launch-external="yes"/>
<allow-intent href="tel:*" />
第二种方法:
通过click事件绑定调用以下方法
src\app\pages\setting\setting.page.ts
onCall(phoneNumber) {
window.location.href = 'tel:' + phoneNumber;
}
4 修改密码页面
参考之前的任务根据需求实现修改密码功能。注册功能和修改密码功能都需要验证两个密码要一致,早期任务
实现的方式比较笨拙,而且没有融入到Angular的表单验证的机制中。可以通过自定义指令以及自定义验证器来
实现。
在shared文件夹下创建directives目录,用于存放自定义的指令。执行下面的命令创建ConfirmDirective:
ionic g directive shared/directives/confirm
添加一个函数confirmValidator。
src\app\shared\directives\confirm.directive.ts
import { Directive, Input } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn } from '@angular/forms';
@Directive({
selector: '[AAAA]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: ConfirmDirective,
multi: true
}
]
})
export class ConfirmDirective implements Validator {
@Input('AAAA') confirm: string;
constructor() { }
validate(control: AbstractControl): ValidationErrors {
return this.confirm ? confirmValidator(this.confirm)(control) : null;
// throw new Error('Method not implemented.');
}
// registerOnValidatorChange?(fn: () => void): void {
// throw new Error('Method not implemented.');
// }
}
export function confirmValidator(confirm: string): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => { // 传入绑定表单的formControl
if ( !control.value ) { // 如果绑定未输入值,则返回 required错误
return {required: true };
}
// 如果两次输入的值不相同,则返回confirm的错误
return control.value !== confirm ? {confirm: {value: true}} : null;
};
}
其中AAAA为这个修改密码函数的名字 换成自己的
在模板文件中添加自定义的属性。
src\app\pages\setting\change-password\change-password.page.html
<ion-header>
<ion-toolbar>
<ion-title>修改密码</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form #passwordForm>
<ion-list>
<ion-item lines="none">
<ion-label position="floating">输入旧密码</ion-label>
<ion-input name="oldPassword" #oldPassword="ngModel" [(ngModel)]="viewObject.oldPassword" required type="password">
</ion-input>
</ion-item>
<ion-item *ngIf="oldPassword.invalid && oldPassword.touched" lines="none">
<ion-text color="danger" *ngIf="oldPassword.errors?.required">
请输入旧密码
</ion-text>
</ion-item>
<ion-text [hidden]="isRight" padding-start color="danger">您输入的旧密码不正确</ion-text>
<ion-item lines="none">
<ion-label position="floating">输入新密码</ion-label>
<ion-input name="newPassword" #newPassword="ngModel" [(ngModel)]="viewObject.newPassword" required type="password" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$">
</ion-input>
</ion-item>
<ion-item *ngIf="newPassword.invalid && newPassword.touched" lines="none">
<ion-text color="danger" *ngIf="newPassword.errors?.required">
请输入新密码
</ion-text>
<ion-text color="danger" *ngIf="newPassword.errors?.pattern">
密码包含大小写字母和数字且长度在8-16位
</ion-text>
</ion-item>
<ion-item lines="none">
<ion-label position="floating">再输入一次新密码</ion-label>
<ion-input name="confirmPassword" #confirmPassword="ngModel" [(ngModel)]="viewObject.confirmPassword" [AAAA]="viewObject.newPassword" required type="password">
</ion-input>
</ion-item>
<ion-item *ngIf="confirmPassword.invalid && confirmPassword.touched" lines="none">
<ion-text color="danger" *ngIf="confirmPassword.errors?.confirm">
两次密码不一致
</ion-text>
<ion-text color="danger" *ngIf="confirmPassword.errors?.required">
请输入确认密码
</ion-text>
</ion-item>
</ion-list>
<div class="ion-padding-horizontal">
<ion-button expand="block" [disabled]="confirmPassword.invalid" (click)="updatePassword()">重置密码</ion-button>
</div>
</form>
</ion-content>
-
这个AAAA配合着上面的ts,两者名字要一样
- 代码显示有些是备注 但实际上全部有用 这里只是没法解析#号
测试通过后,使用自定义验证器修改之前任务中的注册页面。
类似"ng"、“ion”这些前缀,请把默认前缀“app”改成你的专有字符串(姓名拼音首字符)。
5. 关于我们页面
内容包括你的学号、姓名、完成了哪些功能、哪些功能没有完成、通过实训掌握了什么,有什么意见和建议等。
src\app\pages\setting\about-me\about-me.page.html
<ion-header>
<ion-toolbar>
<ion-button href='/setting'>
<ion-icon name="arrow-back"></ion-icon>返回
</ion-button>
<ion-title>关于我们</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card>
<ion-card-header>工程实训</ion-card-header>
<ion-card-content>
<ion-list>
<ion-item>
<ion-label><b>学号:</b></ion-label>
<ion-note slot="end">@@@@@写自己学号</ion-note>
</ion-item>
<ion-item>
<ion-label><b>姓名:</b></ion-label>
<ion-note slot="end">@@@@@写自己名字</ion-note>
</ion-item>
<ion-item>
<ion-label><b>已完成功能:</b></ion-label>
</ion-item>
<ion-item>
<ion-text>
@@@@@写自己完成功能
</ion-text>
</ion-item>
<ion-item>
<ion-label><b>未完成功能:</b></ion-label>
</ion-item>
<ion-item>
<ion-text>
<p>@@@@@写自己未完成功能</p>
</ion-text>
</ion-item>
<ion-item>
<ion-label><b>学习与收获:</b></ion-label>
</ion-item>
<ion-item>
<ion-text>
@@@@@写自己收获
</ion-text>
</ion-item>
<ion-item>
<ion-label><b>意见与建议</b></ion-label>
</ion-item>
<ion-item>
<ion-text>
@@@@@写自己意见和建议
</ion-text>
</ion-item>
</ion-list>
<ion-card-subtitle>日期</ion-card-subtitle>
<div>
<ion-datetime display-format="MM DD, YYYY HH:MM" value="2020-11-12T21:11" disabled="true"></ion-datetime>
</div>
</ion-card-content>
</ion-card>
</ion-content>
- 补齐@@@@@,写自己东西
- 2020-11-12T21:11换成自己时间
6. 修改店铺名称
title和property代表参数的名字,property的值是店铺模型中对应属性的名称。routerLink(路由链接)属性是Angular提供的指令。这个指令
把可点击的 HTML元素绑定到某个路由。点击带有 routerLink指令(绑定到字符串或链接参数数组)的元素
时就会触发一次导航。
在店铺修改页中获取店铺信息页传递过来的参数。
src\app\pages\setting\shop\edit\shop-edit.ts
import { ShopService } from './../shop.service';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { SettingService } from '../../setting.service';
import { ToastController } from '@ionic/angular';
import { LocalStorageService } from 'src/app/shared/services/local-storage.service';
import { ShopPage } from '../shop.page';
import { StatusBar } from '@ionic-native/status-bar/ngx';
@Component({
selector: 'app-shop-edit',
templateUrl: './shop-edit.page.html',
styleUrls: ['./shop-edit.page.scss'],
})
export class ShopEditPage implements OnInit {
title: string;
property: string;
value: any; // 用于ngModel,从shop对象的相关属性中获取数据
constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private shopService: ShopService,
private toastCtrl: ToastController,
private localStorageService :LocalStorageService,
private statusBar:StatusBar
) {
// 沉浸式并且悬浮透明
this.statusBar.overlaysWebView(true);
activatedRoute.queryParams.subscribe(queryParams => {
this.property = queryParams.property;
this.title = queryParams.title;
});
}
ngOnInit() {
}
async onSave() {
const user = this.localStorageService.getUser();
const shop = this.shopService.getShop(user.id);
shop[this.property] = this.value;
this.shopService.updateShop(shop);
this.value = '';
const toast = await this.toastCtrl.create({
message: '保存成功',
duration: 3000
});
toast.present();
this.router.navigateByUrl('/setting/shop');
}
}
为组件添加onSave方法,使用变量对对象的属性进行访问或者赋值。并通过服务把修改后的店铺数据保存到本地存储中。最后页面跳转回到店铺信息页面。
src\app\pages\setting\shop\edit\shop-edit.html
<ion-header>
<ion-toolbar>
<ion-button href='setting/shop'>
<ion-icon name="arrow-back"></ion-icon>返回
</ion-button>
<ion-title>{{title}}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form>
<ion-list>
<ion-item>
<ion-input name="{{property}}" type="text" [(ngModel)]="value" required placeholder="{{title}}"></ion-input>
</ion-item>
</ion-list>
<div padding-horizontal>
<ion-button expand="block" color="primary" (click)="onSave()">保存</ion-button>
</div>
</form>
</ion-content>