• Angular2 + NativeScript 跨平台开发笔记(一)


    NativeScript 是一款跟 ReactNative 对着怼的移动开发技术,其官方钦定了 Angular2 作为推荐的技术框架,那么如何让在浏览器中运行的 Angular2 Web app 项目与 NativeScirpt 项目共享代码呢?

    安装 git

    git 是一个好东西,让我们首先来安装他,但与以往的安装方式稍有不同。
    以下内容 linuxer 可以忽略
    进入 git 官网,下载最新的 git for windows 客户端 https://git-scm.com/
    安装过程大多可以无脑下一步,但是在下面的页面中,要注意一下,勾上Enable symbolic links

    image_1b6e8f1hm6r8issb4i9s9vp09.png-29.8kB

    创建项目仓库

    使用 git init 初始化项目仓库,然后编辑 .git/config 文件,将 symlinks=false 改成 symlinks=true

    建立项目

    使用 angular-cli 与 nativescript-cli 创建项目,建立项目没有特别的地方,安装cli 的说明建立即可,使目录结构如图所示:

    │  .gitignore
    │      
    ├─mobile
    │  │  package.json
    │  │  references.d.ts
    │  │  tsconfig.json
    │  │  
    │  ├─app
    │  │
    │  ├─hooks
    │  │          
    │  ├─node_modules
    │  │                  
    │  └─platforms
    │                              
    └─web
        │  .editorconfig
        │  angular-cli.json
        │  karma.conf.js
        │  package.json
        │  protractor.conf.js
        │  README.md
        │  tslint.json
        │  
        ├─e2e
        │      
        ├─node_modules
        │
        └─src
    

    建立共享代码文件夹

    在 web/src/app 中建立 x-shared 文件夹,表示 cross-platform-shared 的意思。
    然后,cd 到 mobile/app 文件夹中,以管理员身份运行命令行(cmd)并输入:

    mklink /d x-shared ....websrcappx-shared
    

    这样我们就使用软链接建立一个共享文件夹
    linuxer 请使用 ln 命令建立软链接

    然后在任意一个 x-shared 文件夹中建立需要跨平台共享的代码文件,比如负责 http 请求的 service,这里我来做个示例:

    // account.service.ts
    
    import { Http, Headers, RequestOptions, Response } from '@angular/http';
    import { Injectable } from '@angular/core';
    
    // rxjs
    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/observable/throw';
    import 'rxjs/add/operator/catch';
    import 'rxjs/add/operator/map';
    
    import { LoginResult } from '../models/login-result';
    import { ErrorJson } from '../models/error';
    import { Config } from '../config';
    
    
    @Injectable()
    export class AccountService {
        private loginUrl = Config.baseUrl + 'api/account/login';
    
        /**
         * 登录!
         */
        constructor(private http: Http) {
        }
    
        /**
         * 解析消息
         * 
         * @private
         * @param {Response} res
         * @returns {LoginResult}
         * 
         * @memberOf AccountService
         */
        private extractData(res: Response): LoginResult {
            let body = res.json();
            return <LoginResult>body;
        }
    
        /**
         * 错误处理,将错误消息返回,消息形式:错误代码 - 错误详情
         * 
         * @private
         * @param {(Response | any)} error
         * @returns
         * 
         * @memberOf AccountService
         */
        private errorHandler(error: Response | any) {
            let errMsg: string;
            if (error instanceof Response) {
                const body = <ErrorJson>error.json();
                errMsg = `${body.errorMsg}`;
            } else {
                errMsg = error.toString();
            }
            console.log('errMsg');
            return Observable.throw(errMsg);
        }
    
        /**
         * 用户登录
         * 
         * @param {string} usr 用户名
         * @param {string} pwd 明文密码
         * @returns 登录结果
         * 
         * @memberOf AccountService
         */
        login(usr: string, pwd: string) {
            let headers = new Headers({ 'Content-Type': 'application/json' });
            let options = new RequestOptions({ headers: headers });
    
            let data = {
                userName: usr,
                password: pwd
            };
    
            return this.http.post(this.loginUrl, data, options)
                .map(this.extractData)
                .catch(this.errorHandler);
        }
    }
    

    然后分别在两个项目中引用这个 service。

    调用共享的 Service

    就像原先一样来引用共享的 service

    // web 版的登录入口
    
    import { Component, OnInit } from '@angular/core';
    
    import { AccountService, LoginResult, ErrorJson } from 'x-shared'; // 就像原先一样来引用共享的 service
    
    import { LocalNoticeService, LocalNoticeType } from 'shared/notice.service';
    
    @Component({
        selector: 'nav-account',
        templateUrl: './nav-account.component.html',
        styleUrls: ['./nav-account.component.css'],
        providers: [AccountService]
    })
    export class NavAccountComponent implements OnInit {
    
        constructor(
            private account: AccountService,
            private localNoticeService: LocalNoticeService // 这是在网页弹窗的消息服务
        ) {
        }
    
        login(usr: string, pwd: string) {
            if (usr === '' || pwd === '') {
                // 在网页上显示一个提醒
                this.localNoticeService.showMsg('登录失败', '请输入用户名和密码!', LocalNoticeType.error);
                return;
            }
            // 跨平台的登录功能
            this.account.login(usr, pwd)
                .subscribe(
                (res: LoginResult) => {
                    this.localNoticeService.showMsg('登录成功', '', LocalNoticeType.success);
                },
                (error: string) => {
                    this.localNoticeService.showMsg('登录失败', error, LocalNoticeType.error);
                });
        }
    
        ngOnInit() { }
    }
    
    // 手机上面的登录页面
    
    import { Component, OnInit } from '@angular/core';
    import * as dialogs from 'ui/dialogs';
    
    import { AccountService, LoginResult } from '../../x-shared'; // 就像原先一样来引用共享的 service
    
    @Component({
        selector: 'login',
        templateUrl: './pages/login/login.component.html',
        providers: [AccountService]
    })
    
    export class LoginComponent implements OnInit {
    
        constructor(private account: AccountService) { }
    
        ngOnInit() { }
    
        login(usr: string, pwd: string) {
            if (usr === '' || pwd === '') {
            // 调用原生的 API 弹窗提示
                dialogs.alert({
                    message: '请填写用户名和密码!',
                    okButtonText: '确定'
                });
                return;
            }
            // 跨平台的登录功能
            this.account.login(usr, pwd)
                .subscribe(
                (res: LoginResult) => {
                    let options: dialogs.AlertOptions = {
                        title: '登陆成功',
                        message: `${res.token.authToken}
                        ${res.token.refreshToken}`,
                        okButtonText: '确定'
                    };
                    dialogs.alert(options).then(() => console.dir(res));
                },
                (err: string) => {
                    let options: dialogs.AlertOptions = {
                        title: '登陆失败',
                        message: err,
                        okButtonText: '确定'
                    };
                    dialogs.alert(options);
                });
        }
    }
    

    效果!
    web 网页
    web.gif-415kB

    手机移动端
    mobile.gif-594.5kB

    至此,我们就实现了网页版与手机客户端共享一套代码的功能,一旦 service 需要发生变动,只需要更改任意一个 x-shared 文件夹的代码,更改就会同时作用到另一个项目上。

    注意!

    • 在 windows10 创造者更新之前,创建软链接需要管理员权限,请确保通过使用带有管理员权限的命令行来克隆仓库

    • windows 下的软链接只在 Vista 以上的 windows 系统中起作用

  • 相关阅读:
    [CF1475F] Unusual Matrix
    [JXOI2018] 游戏
    [ZJOI2010] 排列计数
    [CF1474E] What Is It?
    [CF375D] Tree and Queries
    [CF519E] A and B and Lecture Rooms
    [CF321C] Ciel the Commander
    [CF1C] Ancient Berland Circus
    [CF321A] Ciel and Robot
    [CF1450C1] Errich-Tac-Toe (Easy Version)
  • 原文地址:https://www.cnblogs.com/JacZhu/p/6286007.html
Copyright © 2020-2023  润新知