利用Ionic2 + angular4实现一个地区选择组件


Posted in Javascript onJuly 27, 2017

前言

本文主要给大家介绍的是关于利用Ionic2 + angular4实现一个地区选择组件的相关内容,为什么会有这篇文章?主要是因为最近在项目重构的过程中,发现之前用mobiscroll写的地区选择指令在angular2中很难重用(毕竟是用typeScript)。于是就萌生了自己写一个组件的想法。

想和之前一样基于mobiscroll去写,但是发现非常耗费精力,于是某日万般无奈这下搜了一下相关的组件,不出所料已经有人写了。https://www.npmjs.com/package...但是此组件并不符合我的要求。我不是单纯的选择省市区,还可能是选择省市或者省。于是参照此项目基于ionic2的picker写了一个公用组件。下面话不多说了,感兴趣的朋友们下面来一起看看详细的介绍:

具体代码如下:

AreasSelect.ts

import {PickerController} from "ionic-angular";
import {Component, EventEmitter, Output, Input} from "@angular/core";
import {areasList} from "../../datasource/areas";

@Component({
 selector: 'areas-select',
 templateUrl: 'areasSelect.com.html',
})
export class AreasSelect {
 constructor(protected Picker: PickerController) {
 }
 private picker;
 private provinceCol = 0; // 省列
 private cityCol = 0; // 市列
 private regionCol = 0; // 区列
 private pickerColumnCmps; // picker纵列数据实例
 private isOpen = false; // 是否被创建
 private pickerCmp; // picker 实例
 private value = ''; // 选中后的数据
 @Input() citiesData = areasList; // 地区数据(默认为areas.ts的数据)
 @Input() cancelText = '关闭'; // 关闭按钮文本
 @Input() doneText = '完成'; // 完成按钮文本
 @Input() separator = ''; // 数据衔接模式
 @Input() level = 3; // 等级设置 最高为三级
 /**
 * 关闭时触发的事件
 * 没有值返回
 * @type {EventEmitter}
 */
 @Output() cancel: EventEmitter<any> = new EventEmitter(); // 关闭事件
 /**
 * 完成时触发的事件
 * 返回值为obj
 * obj = {data: object,value: string} data为对应的省市区和编码
 * @type {EventEmitter}
 */
 @Output() done: EventEmitter<any> = new EventEmitter(); // 完成事件
 /**
 * 打开地区选择器
 * 基本思路
 * 1.创建picker
 * 2. 先把数据处理成省市区分开的数组
 * 3. 将数据以列的形式给到picker
 * 4. 设置数据显示样式(picker)
 * 5. 生成picker
 */
 private open() {
 let pickerOptions = {
 buttons: [
 {
 text: this.cancelText,
 role: 'cancel',
 handler:() => {
 this.cancel.emit(null);
 }
 },
 {
 text: this.doneText,
 handler: (data) =>{
 this.onChange(data);
 this.done.emit({
 data: data,
 value: this.value
 });
 }
 }
 ]
 };
 this.picker = this.Picker.create(pickerOptions);
 this.generate();// 加载
 this.validate(this.picker); // 渲染
 this.picker.ionChange.subscribe(() => {
 this.validate(this.picker);
 });
 // 生成
 this.picker.present(pickerOptions).then(() => {
 this.pickerCmp = this.picker.instance;
 this.pickerColumnCmps = this.pickerCmp._cols.toArray();
 this.pickerColumnCmps.forEach(function (col) {
 return col.lastIndex = -1;
 });
 });
 this.isOpen = true;
 this.picker.onDidDismiss(function () {
 this.isOpen = false;
 });
 }

 /** 对数据进行处理,并移交给picker
 *
 */
 private generate() {
 let values = this.value.toString().split(this.separator);
 // Add province data to picker
 let provinceCol = {
 name: 'province',
 options: this.citiesData.map(function (province) {
 return {text: province.name, value: province.code, disabled: false};
 }),
 selectedIndex: 0
 };
 let provinceIndex = this.citiesData.findIndex(function (option) {
 return option.name == values[0];
 });
 provinceIndex = provinceIndex === -1 ? 0 : provinceIndex;
 provinceCol.selectedIndex = provinceIndex;
 this.picker.addColumn(provinceCol);
 // Add city data to picker
 let cityColData = this.citiesData[provinceCol.selectedIndex].children;
 let cityCol;

 if (this.level >= 2) {
 cityCol = {
 name: 'city',
 options: cityColData.map(function (city) {
 return {text: city.name, value: city.code, disabled: false};
 }),
 selectedIndex: 0
 };
 let cityIndex = cityColData.findIndex(function (option) {
 return option.name == values[1];
 });
 cityIndex = cityIndex === -1 ? 0 : cityIndex;
 cityCol.selectedIndex = cityIndex;
 this.picker.addColumn(cityCol);
 }
 // Add region data to picker
 let regionData, regionCol;

 if (this.level === 3) {
 regionData = this.citiesData[provinceCol.selectedIndex].children[cityCol.selectedIndex].children;
 regionCol = {
 name: 'region',
 options: regionData.map(function (city) {
 return {text: city.name, value: city.code, disabled: false};
 }),
 selectedIndex: 0
 };
 let regionIndex = regionData.findIndex(function (option) {
 return option.name == values[2];
 });
 regionIndex = regionIndex === -1 ? 0 : regionIndex;
 regionCol.selectedIndex = regionIndex;
 this.picker.addColumn(regionCol);
 }
 this.divyColumns(this.picker);
 }

 /**设置数据显示样式
 * @param picker
 */
 private divyColumns(picker) {
 let pickerColumns = this.picker.getColumns(); // 获取列数据
 let columns = [];
 pickerColumns.forEach(function (col, i) {
 columns.push(0);
 col.options.forEach(function (opt) {
 if (opt && opt.text && opt.text.length > columns[i]) {
 columns[i] = opt.text.length;
 }
 });
 });
 if (columns.length === 2) {
 let width = Math.max(columns[0], columns[1]);
 pickerColumns[0].align = 'right';
 pickerColumns[1].align = 'left';
 pickerColumns[0].optionsWidth = pickerColumns[1].optionsWidth = width * 17 + "px";
 }
 else if (columns.length === 3) {
 let width = Math.max(columns[0], columns[2]);
 pickerColumns[0].align = 'right';
 pickerColumns[1].columnWidth = columns[1] * 33 + "px";
 pickerColumns[0].optionsWidth = pickerColumns[2].optionsWidth = width * 17 + "px";
 pickerColumns[2].align = 'left';
 }
 }

 /**
 * 验证数据
 * @param picker
 */
 private validate(picker) {
 let _this = this;
 let columns = picker.getColumns();
 let provinceCol = columns[0];
 let cityCol = columns[1];
 let regionCol = columns[2];
 if (cityCol && this.provinceCol != provinceCol.selectedIndex) {
 cityCol.selectedIndex = 0;
 let cityColData = this.citiesData[provinceCol.selectedIndex].children;
 cityCol.options = cityColData.map(function (city) {
 return {text: city.name, value: city.code, disabled: false};
 });
 if (this.pickerColumnCmps && cityCol.options.length > 0) {
 setTimeout(function () {
 return _this.pickerColumnCmps[1].setSelected(0, 100);
 }, 0);
 }
 }
 if (regionCol && (this.cityCol != cityCol.selectedIndex || this.provinceCol != provinceCol.selectedIndex)) {
 let regionData = this.citiesData[provinceCol.selectedIndex].children[cityCol.selectedIndex].children;
 regionCol.selectedIndex = 0;
 regionCol.options = regionData.map(function (city) {
 return {text: city.name, value: city.code, disabled: false};
 });
 if (this.pickerColumnCmps && regionCol.options.length > 0) {
 setTimeout(function () {
 return _this.pickerColumnCmps[2].setSelected(0, 100);
 }, 0);
 }
 }
 this.provinceCol = provinceCol.selectedIndex;
 this.cityCol = cityCol ? cityCol.selectedIndex : 0;
 this.regionCol = regionCol ? regionCol.selectedIndex : 0;
 }

 /**
 * 设置value
 * @param newData
 */
 private setValue(newData) {
 if (newData === null || newData === undefined) {
 this.value = '';
 }
 else {
 this.value = newData;
 }
 }

 /**
 * 获取value值
 * @returns {string}
 */
 private getValue() {
 return this.value;
 }

 /**
 * 改变value值的显示
 * @param val
 */
 private onChange(val) {
 this.setValue(this.getString(val));
 }

 /**
 * 获取当前选择的地区数据
 * @param newData
 * @returns {string}
 */
 private getString(newData) {
 if (newData['city']) {
 if (newData['region']) {
 return "" + newData['province'].text + this.separator + (newData['city'].text || '') + this.separator + (newData['region'].text || '');
 }
 return "" + newData['province'].text + this.separator + (newData['city'].text || '');
 }
 return "" + newData['province'].text;
 }
}

areasSelect.com.html

其实是不需要对应的template的,但是为了能和父级传参,这里创建了一个空的template

<div></div>

具体用法:

在需要用到的页面调用

test.page.html

<ion-content>
 <button ion-button block icon-left color="light" (tap)="showAreasSelect()">地区选择</button>
</ion-content>
<areas-select #areasSelect [level]="3" (cancel)="closeSelect()" (done)="done($event)"></areas-select>

test.page.ts

import {Component, ElementRef, Injector, ViewChild} from "@angular/core";
import {BasePage} from "../base.page";

@Component({
 templateUrl: 'test.page.html',
 styles: []
})
export class TestPage extends BasePage {
 constructor(protected rt: ElementRef, protected ij: Injector) {
 super(rt, ij);
 }
 @ViewChild('areasSelect') areasSelect;
 showAreasSelect() {
 this.areasSelect.open();
 }
 done(data) {
 this.showAlert(JSON.stringify(data));
 }
 closeSelect() {
 this.showAlert('you click close');
 } 
}

没有地区数据json或ts的文件可以去这里获取:http://xiazai.3water.com/201707/yuanma/regional_data(3water.com).rar

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
权威JavaScript 中的内存泄露模式
Aug 13 Javascript
javascript prototype,executing,context,closure
Dec 24 Javascript
css结合js制作下拉菜单示例代码
Feb 27 Javascript
jQuery计算文本框字数及限制文本框字数的方法
Mar 01 Javascript
js实现精确到秒的倒计时效果
May 29 Javascript
解析JavaScript模仿块级作用域
Dec 29 Javascript
微信小程序 封装http请求实例详解
Jan 16 Javascript
微信小程序中显示html格式内容的方法
Apr 25 Javascript
利用Blob进行文件上传的完整步骤
Aug 02 Javascript
layui 根据后台数据动态创建下拉框并同时默认选中的实例
Sep 02 Javascript
vue中@change兼容问题详解
Oct 25 Javascript
jQuery操作事件完整实例分析
Jan 10 jQuery
vue单页应用中如何使用jquery的方法示例
Jul 27 #jQuery
详解win7 cmd执行vue不是内部命令的解决方法
Jul 27 #Javascript
Vue2.0如何发布项目实战
Jul 27 #Javascript
在Vue中如何使用Cookie操作实例
Jul 27 #Javascript
vue 怎么创建组件及组件使用方法
Jul 27 #Javascript
详解Angular-cli生成组件修改css成less或sass的实例
Jul 27 #Javascript
Vue中如何实现轮播图的示例代码
Jul 27 #Javascript
You might like
PHP3 safe_mode 失效漏洞
2006/10/09 PHP
phpmyadmin导入(import)文件限制的解决办法
2009/12/11 PHP
Jquery ajax执行顺序 返回自定义错误信息(实例讲解)
2013/11/06 Javascript
简介JavaScript中的setTime()方法的使用
2015/06/11 Javascript
javascript实现动态标签云
2015/10/16 Javascript
浅谈Sublime Text 3运行JavaScript控制台
2016/06/06 Javascript
js实现的页面加载完毕之前loading提示效果完整示例【附demo源码下载】
2016/08/02 Javascript
解决node.js安装包失败的几种方法
2016/09/02 Javascript
JS动态添加选项案例分析
2016/10/17 Javascript
js实现刷新页面后回到记录时滚动条的位置【两种方案可选】
2016/12/12 Javascript
原生js实现弹出层效果
2017/01/20 Javascript
Vuex和前端缓存的整合策略详解
2017/05/09 Javascript
Bootstrap弹出框(Popover)被挤压的问题小结
2017/07/11 Javascript
微信小程序排坑指南详解
2018/05/23 Javascript
js隐式转换的知识实例讲解
2018/09/28 Javascript
详解vue-cli 2.0配置文件(小结)
2019/01/14 Javascript
详解vue 命名视图
2019/08/14 Javascript
js的Object.assign用法示例分析
2020/03/05 Javascript
element日历calendar组件上月、今天、下月、日历块点击事件及模板源码
2020/07/27 Javascript
Python中的匿名函数使用简介
2015/04/27 Python
给Python入门者的一些编程建议
2015/06/15 Python
python编程羊车门问题代码示例
2017/10/25 Python
Python实现程序判断季节的代码示例
2019/01/28 Python
selenium+Chrome滑动验证码破解二(某某网站)
2019/12/17 Python
Python Django form 组件动态从数据库取choices数据实例
2020/05/19 Python
详解如何通过H5(浏览器/WebView/其他)唤起本地app
2017/12/11 HTML / CSS
军神教学反思
2014/02/04 职场文书
yy司仪主持词
2014/03/22 职场文书
安全生产先进个人事迹材料
2014/12/30 职场文书
面试感谢信范文
2015/01/22 职场文书
2015年银行信贷员工作总结
2015/05/19 职场文书
工作后的感想
2015/08/07 职场文书
小学英语教师研修感悟
2015/11/18 职场文书
用Python编写简单的gRPC服务的详细过程
2021/07/04 Python
利用Java连接Hadoop进行编程
2022/06/28 Java/Android
类和原型的设计模式之复制与委托差异
2022/07/07 Javascript