Hi~大家好,我是一名前端开发工程师,目前主要使用Angular、Vue来进行开发,来掘金社区挺久,第一次发帖子,请大家多多指教。
介绍 Ionic
小编目前正在使用Ionic3和Ionic5在做开发,下面简单介绍一下Ionic3。
- Ionic 是基于Angular和Cordova结合开发出来的HTML5混合移动应用框架,可以快速创建一个跨平台的移动应用。
- Ionic和Angular的关系:在Angular的基础上再做了一层封装,让我们可以使用Angular语法更快速和容易开发项目。
- Ionic和Cordova关系:Ionic调用原生功能基于Cordova,Cordova提供JavaScript调用Native功能。
- Ionic5已经额外支持Vue和React结合一起开发,而且开发起来也很舒服。Ionic5和Ionic3区别还是有点大,因为小编是最近才开始使用Ionic5,了解的还不够深,就不继续往下说了,有兴趣的可以去官网了解下。
安装项目、命令行相关
- 可以通过官方提供的CLI脚手架来搭建项目
npm install -g @ionic/cli
- 下载完成后搭建一个项目
ionic start myApp tabs
- 因为npm下载的@ionic/cli 默认是最新版本的脚手架,所以在搭建项目时默认会搭建ionic5项目,如果需要搭建ionic3项目,更换以下这个命令行即可:
ionic start tabTest --type=ionic-angular
- 搭建完成后我们使用 ionic serve 这个命令行来运行项目
ionic serve
- Ionic3 启动成功显示界面
- 成功启动之后我们需要通过命令行来创建文件夹
ionic g component|page|provider|pipe 文件名
封装通讯录
这里开始正式介绍一下怎么样在Ionic里面封装一个通讯录。
- 首先我们先创建一个Page的文件
ionic g page addressBook
- 创建成功我们首先在pages文件下的home.html写入一个button触发点击事件弹出addressBook
<button (click)="goToAddressBookCom()">goToAddressBookCom</button>
- 接着在home.ts文件引入ModalController包控制弹出addressBook
import { ModalController } from 'ionic-angular';
- 在constructor中注册
constructor(public modalCtrl: ModalController) { }
- 接下来定义注册我们的click方法并且使用ModalController来弹出组件
goToAddressBookCom() {
let modal = this.modalCtrl.create('AddressBookPage');
modal.present();
}
这里是成功弹出来的addressBook:
- 这里讲解一下写这个通讯录的思路:
- 首先无非就是左右两边的实现联动,怎样联动?
侧边栏控制通讯栏:
- 侧边栏:可以根据touchmove事件判断手指的滑动来做判断,还有点击当前的字母DOM元素来判断
- 通讯栏:获取通列表DOM元素,根据侧边栏最终得到的Key值和通讯列表的innerHTML做判断,成功判断出来的获取它距离顶部的offsetTop,然后使用父元素.scrollTo(x,y)跳转到对应的起始位置。
通讯栏控制侧边栏:
- 通讯栏:首先使用一个空对象,分别记录所有Key分别距离元素顶部的距离,然后使用addEventListener监听通讯栏的scroll事件,实时获取当前滚动距离,判断当前滚动距离是否大于等于当前记录Key的高度,判断满足就直接改变控制侧边栏的Key值
下面把几个文件的代码写进来给大家参考:
- addressBook.ts文件我们先定义好数据
// 我们属需要的数据结构是这样的
// 用 key作为通讯列表的标示: # A - Z
datas=[
{
"key": "#",
"data": [
{
"code": "CN",
"name": "中國"
},
]
},
{
"key": "A",
"data": [
{
"code": "AU",
"name": "澳大利亞"
},
]
},
{
"key": "B",
"data": [
{
"code": "BE",
"name": "比利時"
},
]
},
// ........
]
- 下面我们来书写html、css和ts代码
- html
<div id="areaContent">
<div class="all-container" #container>
<!-- 通讯栏 -->
<div id="container" class="list-container">
<div class="items" *ngFor="let val of address_book_datas;let i = index;">
<div class="tag">{{val.key}}</div>
<ul class="items-list-select">
<li *ngFor="let keyValue of val.data;let keyIndex=index;" (click)="onItemClick(keyValue)">
<span>{{keyValue.name}}</span>
<span>{{keyValue.code}}</span>
</li>
</ul>
</div>
</div>
</div>
<!-- 侧边栏 -->
<div id="letters" class="letters-scroll">
<div class="items" *ngFor="let val of address_book_datas;let i = index;"
[ngStyle]="{'color':lettersActiveType == val.key.trim() ? '#20AECE' : '#ccc'}">
{{val.key}}
</div>
</div>
</div>
- css
page-address-book {
#areaContent {
display: flex;
max-height: 100vh;
overflow: hidden;
}
.all-container {
margin-top: 20px;
width: 100%;
min-height: 100vh;
padding-left: 15px;
padding-right: 3px;
overflow-y: scroll;
z-index: 10;
}
.list-container {
>.items {
>.tag {
background-color: #f4f4f9;
margin-right: 21px;
}
>.items-list-select {
padding-left: 0;
>li {
margin-right: 25px;
display: flex;
justify-content: space-between;
color: #342648;
font-size: 17px;
border-bottom: 1px solid #eae9ef;
>span {
margin: 13px 0;
}
}
}
}
}
#letters {
margin-top: 20px;
width: 15px;
position: absolute;
max-height: 100vh;
right: 6px;
top: 50%;
overflow: hidden;
transform: translateY(-50%);
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
color: #ccc;
background-color: #fff;
border-radius: 5px;
display: flex;
flex-direction: column;
justify-content: center;
z-index: 100;
overflow-y: hidden;
>.items {
width: 100%;
display: block;
text-align: center;
padding: 4px 0;
font-size: 12px;
}
}
}
- ts
import { Component, ViewChild, NgZone, ElementRef } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
@IonicPage()
@Component({
selector: 'page-address-book',
templateUrl: 'address-book.html',
})
export class AddressBookPage {
// 通讯录数据(这里我就不提供了,大家自己随便弄几个就好了)
address_book_datas:any = [];
// 获取元素通讯录dom元素
Container: any;
@ViewChild('container') container: ElementRef;
// 获取侧边栏dom元素
tagList: any;
tagEle: any;
// 默认起始位置从 # 开始
lettersActiveType: string = '#';
constructor(public navCtrl: NavController, public navParams: NavParams) {}
ionViewDidLoad() {
this.Container = this.container.nativeElement;
this.tagList = document.querySelectorAll('.tag');
//启动监听事件
this.addEventLetters();
this.addEventContainer();
}
// 监听侧边栏 A-Z 事件
addEventLetters() {
let letterDom = document.getElementById('letters');
//监听侧边栏手指滑动事件
letterDom.addEventListener('touchmove', (event: any) => {
event.preventDefault();
let y = event.touches[0].clientY
let x = event.touches[0].clientX
//根据当前纵向坐标控制内容的位置
let MaxL = letterDom.getBoundingClientRect().left;
let MaxR = letterDom.getBoundingClientRect().right;
let MaxT = letterDom.getBoundingClientRect().top
let MaxB = letterDom.getBoundingClientRect().top + letterDom.getBoundingClientRect().height;
if ((x >= MaxL && x <= MaxR) && (y >= MaxT && y <= MaxB) && x && y) {
this.tagEle = document.elementFromPoint(x, y);
let eleContent = this.tagEle.innerHTML.trim();
this.lettersActiveType = eleContent;
this.goToLetter(eleContent);
}
});
//滑动侧边栏点击事件
letterDom.addEventListener('click', (event: any) => {
event.preventDefault();
let eleContent = event.target.innerHTML.trim();
this.lettersActiveType = eleContent;
this.goToLetter(eleContent);
})
// 移除侧边栏touchmove事件
letterDom.addEventListener("touchend", function (e) {
letterDom.removeEventListener("touchmove", function () {
console.log('移除touchmove事件')
}, false);
});
}
// 监听通讯录 A-Z事件
addEventContainer() {
let containerListDom: any = document.querySelectorAll('#container >.items');
let tagList: any = document.querySelectorAll('#container >.items >.tag');
let tagsHeight: any = {};
//获取通讯列表每个Key距离父元素顶部距离
for (let index = 0; index < containerListDom.length; index++) {
let key = tagList[index].innerHTML;
tagsHeight[`${key}`] = containerListDom[index].offsetTop;
}
//监听取通讯列当前滚动位置是否大于等于当前Key距离顶部位置,然后改变侧边栏的key值,从而实现联动
this.Container.addEventListener('scroll', (event: any) => {
for (const key in tagsHeight) {
if (event.target.scrollTop >= tagsHeight[key]) {
this.lettersActiveType = key;
}
}
})
}
// 点击侧边栏字母
jumpTag(type) {
this.lettersActiveType = type;
this.goToLetter(type);
}
// 跳转到对应Key起始位置
goToLetter(Letter) {
for (let index = 0; index < this.tagList.length; index++) {
if (Letter === '#') {
this.Container.scrollTo(0, 0, 0);
break;
}
else if (this.tagList[index].innerHTML == Letter) {
const goToHeiht = this.tagList[index].offsetTop;
this.Container.scrollTo(0, goToHeiht, 0);
break;
}
}
}
// 获取点击所选国家值
onItemClick(data) {
console.log(data);
}
}
最终效果图
其实这种写法在Vue还有原生开发也适用,只不过是换一下写法
这是我第一次写博客,可能有很多写得不好的地方或者描述的不清楚的地方,希望大家可以提供一些改善的建议,请多多指教。
文中如有不对的地方欢迎各位小伙伴多多指正~
谢谢大家💖~