65.9K
CodeProject 正在变化。 阅读更多。
Home

Angular 购物车用于联盟营销 - Angular 5

2015 年 2 月 27 日

CPOL

19分钟阅读

viewsIcon

196547

downloadIcon

7154

Angular 5 中的联盟营销 Angular 购物车,具有响应式电视广告和强大的功能,可推动实际销售,例如无限的分销商 ID 用于佣金,并附带编辑器。

点击此处查看此 Angular 购物车的实际演示

点击此处查看此购物车的进阶版本

观看演示购物车功能的视频

用于联属营销的 Angular 5 购物车

我已将本文和示例项目更新至 Angular 5。原始文章和 AngularJS 购物车项目可在以下网址找到

http://www.software-rus.com/articles/articles.html?article=AngularResponsiveCart

许多人希望在线销售产品,但他们没有任何产品可供销售。而且,许多人希望其他人销售他们拥有的产品,但不知道如何找到这些人。这个带有视频的 Angular 5 购物车的传销和联属营销解决了这两个问题。您可以将此购物车(里面装满您的产品)提供给经销商,让他们放在自己的网站上,它将把来自任何商家账户提供商(如 PayPal)的订单传递给您,并附带订单来源经销商的经销商 ID,以便您可以向他们支付佣金。此外,您还可以向经销商提供一个带有其经销商 ID 的链接,这些带有传递的经销商 ID 的订单将传递到 PayPal 或任何指定的商家提供商。

此项目中的购物车包括播放来自世界各地服务器视频的功能。原因在于,当今世界购物车的图片在传达产品购买益处方面效果不佳。视频是一种电视广告,研究表明其在产生销售方面效率高出数千倍。例如,中国的优酷服务器现在是世界上最大的电视网络,您可以在优酷服务器上免费发布您的视频(电视广告),并在本购物车中播放它们,而不是展示一张无聊的产品图片。

有很多人不精通电脑或互联网,但他们需要一个简单的购物车,不需要数据库或程序员来安装。我记得有一次一位客户打电话给我寻求我的某个软件程序的技术支持,他告诉我“你的软件不工作!”我问问题出在哪里,他说他踩在“脚踏板”上,但什么也没发生。结果是,他把鼠标放在地上,以为必须用脚踩。不用说,帮助他是一个挑战。

首先,我想要包含一个 Pinterest 风格的布局,所以我决定使用一个我在购物车中经常看到的常用布局,即 Codrops 著名的 ViewModeSwitch,您可以在以下网址找到它:https://github.com/codrops/ViewModeSwitchViewModeSwitch 是一个 CSS Pinterest 风格的布局,在许多商业购物中都有使用,并且与 AngularJS 配合良好,只需进行少量更改。

这是购物车的视频演示

Angular 5 电视购物车功能

以下是我包含的一些实用功能

  • 使用 Angular CLI 和 Typescript 编写。
  • 能够获取佣金支付佣金
  • 在 Angular 5 中使用 APP_INITIALIZER 在应用程序启动之前读取配置和产品数据
  • 增加了易于定制的运费和手续费。
  • 扩展了 PayPal 功能,包括通知和取消页面。
  • 必须包含 Bootstrap 3 添加 ui.bootstrap
  • 必须是响应式的,以便在任何移动设备上完美显示和滚动。
    使用此购物车移动应用程序的示例:www.SerGioApps.com
  • 必须有一个酷炫、响应式的 Bootstrap 菜单。
  • 允许在我们的购物车中使用多家商店
  • 必须从内部 JSON 文本文件中读取产品及其描述。
  • 必须使用 JSONP 从外部 JSON 文本文件中读取产品及其描述。
  • 除了产品图片,还必须能够播放产品的视频(电视广告),视频可来自全球数百个视频服务器。必须能够播放上传到中国优酷服务器的视频,优酷现已成为全球最大的电视网络。
  • 至少必须包括 PayPal、Google Wallet Stripe 的商家网关。
  • 必须可扩展,以便轻松添加新功能,如支付方式。
  • 必须允许免费产品,这些产品不能使用虚假参数添加到购物车
  • 必须使用 Angular 5 处理 Google Analytics
  • 必须能够包含指向第三方网站(如 Google Play 等)的链接。
  • 必须具有允许其“直接放置”在任何现有网站的根目录的目录结构。
  • 必须将选定的文本显示为 HTML,以便在视觉上吸引潜在客户。
  • 必须能够以 Pinterest 风格布局列表视图布局显示产品
  • 必须包含滑动按钮分页以控制每页显示的产品数量
  • 必须包含过滤和排序选项
  • 必须能够为 Angular 网站创建经销商链接以用于经销商佣金

安装 Node.js 以开始

如果您是 PC (Windows) 或 OS X (Mac) 用户,您可以使用安装程序从以下网址安装最新版本的 Node:
https://node.org.cn/en/download/ 并按照步骤操作。

如果您在 Windows 上安装最新版本,您可能会遇到各种错误,需要花费数小时搜索互联网才能解决。一种可能的解决方案是允许安装程序设置环境变量 PATH(这是设置中的默认设置),而是手动设置环境变量 PATH。

此时,如果您尝试使用 npm,有些人会遇到可怕且现在著名的错误

npm ERR! Windows_NT 6.1.7601  

如果您在代理后面,此错误有许多可行的修复方法,但如果您不在代理后面,那么尝试修复此错误可能会让您抓狂。要修复此错误,或者如果您刚刚更新到最新版本的 npm,请以管理员身份启动 CMD 窗口并运行以下命令

npm config delete http-proxy
npm config delete https-proxy
npm config delete proxy -g
npm config delete http-proxy -g

// THE REAL MAGIC TO FIXING THIS ERROR IS:
npm config set registry "http://registry.npmjs.org"
npm config set strict-ssl false

如果安装 npm 后仍然出现此错误:

<code>events.js:72
        throw er; // Unhandled 'error' event</code>

这很可能是因为您在 Windows 7 或更高版本上未使用正确的代码页。在 Windows 上,代码页应设置为 850,而不是 437,但是请注意设置 代码页为 850,因为如果操作不正确,您的 Windows 计算机可能无法再次启动。在尝试此操作之前,请研究设置代码页为 850 的正确方法。

让我们使用 Angular 5 CLI

安装 Angular CLI,它也会将 Angular 的“ng”命令全局安装到您的系统上,如下所示。

此时,Angular 5 应使用以下命令安装。我暂时不会深入探讨 Angular 5 的安装,因为您可以在互联网上找到大量相关文档。我将把本文的重点放在 Angular 5 移动应用程序的源代码上。

安装 Angular-CLI 的说明可在以下网址找到:https://github.com/angular/angular-cli#updating-angular-cli

我们应该从理解 Webpack、System.js 和 angular-cli 开始。System.js 在 Angular 2 构建初期被大量使用。Webpack 随后发展起来,最后,现在的实际标准 Angular CLI 发展成为 Webpack 的一种包装器,并帮助轻松搭建新项目和创建组件。安装 angular-cli 也将在您的系统上全局安装 Angular 的“ng”命令:安装 angular-cli 的说明在:

https://github.com/angular/angular-cli#updating-angular-cli

npm uninstall -g angular-cli
npm uninstall --save-dev angular-cli
npm uninstall --save-dev angular/cli
npm uninstall -g @angular/cli
npm cache clean
Delete the C:\Users\YOU\AppData\Roaming\npm\node_modules\@angular folder.
Reboot, then, finally, run:
npm install -g @angular/cli@latest
To verify whether your installation
completed successfully, you can run:

ng version

@angular/cli: 1.3.1
node: 7.4.0
os: win32 x64

安装我们的 Angular 5 购物车

下载并解压本文顶部的“cart-app.zip”文件,并将解压后的文件夹“cart-app”放入您用于 Angular 项目的任何目录中。在我的电脑上,我有一个名为“Angular”的目录。这个目录的名称可以随心所欲。在该目录中,使用管理员模式的 CMD 提示符,并在 cart-app 文件夹中运行以下命令

Select a folder - I used C:\Angular and put the unzipped 'cart-app' folder in there and run:

<a href="file:///C:/Angular%3Ec">C:\Angular>c</a>art-app>npm install 

这将安装 node_modules 文件夹,它非常大,请耐心等待。接下来,我们将使用 Visual Studio Code IDE(它在 Windows 和 Mac 计算机上都能很好地工作),并在此编辑器中构建 Angular 5 App

安装和使用 Visual Studio Code IDE

我使用了 Microsoft 的 Visual Studio Code IDE,您可以从以下网址轻松下载并安装: https://vscode.js.cn/

打开 Visual Studio Code 并选择项目文件夹“first-app”,然后打开集成终端窗口,如下所示。在 Visual Studio Code集成终端窗口中运行以下命令,它将为您的完成项目创建“dist”目录。

然后从 IDE 运行以下命令

C:\Angular>mobile-app>ng build
C:\Angular>mobile-app>ng serve

这将启动我们的 Node.js 服务器,运行在 4200 端口,因此如果您在 Chrome 浏览器中打开 https://:4200,您将看到应用程序正在运行。这将运行 Angular CLI 自带的默认 Angular 应用程序。

运行应用程序时可能会出现什么问题?

许多用户会遇到此错误

Module build failed: TypeError: Cannot read property 'newLine' of undefined

当您收到此错误时,通常是由不正确的 Angular - CLI 版本引起的。一种有效的解决方法是运行

npm uninstall-g @angular/cli
npm clean cache
npm install Last-g @angular/cli @
then remove the local node_modules folder and run:
install npm–Save-dev @angular/cli @ Last
npm install

您必须随时关注最新变化:
https://github.com/angular/angular-cli#updating-angular-cli

如何使用预编译(AOT)编译 Angular 5 应用程序

为什么选择预编译 (AOT) 而不是即时编译 (JIT)?

  • 渲染速度更快,因为应用程序的预编译版本已下载。
  • 异步请求数量大大减少。
  • AOT 确保所有内容都构建到一个文件中(至少对于您的代码而言)。
  • Angular 框架大小大大缩小。
  • AOT 还会确保您的应用程序“编写良好”,这可能会很麻烦。

截至 2017 年 1 月,如果您正在使用 angular-cli,运行命令 ng build --prod 时,AOT 编译现在是默认的编译方法,无需更改代码。

我将在这里提前解释如何为移动设备构建“www”文件夹。编译 Angular 5 应用程序以使其在文件夹外运行的“大秘密”并不明显。要构建一个 Angular 5 应用程序使其工作,需要正确设置路径。查看您添加到项目的 src 文件夹中的 index.html,您会注意到在 index.html 文件中我们替换了

<base href="../" />

<script>document.write('<base href="' + document.location + '" />');<script>

当您刷新页面时,这会将基本 href 动态设置为您当前的 document.location。

如果您查看 app.routing.ts,您会发现我已确保我们在 app.routing.ts 中使用了 哈希标签位置

@NgModule({ imports: [RouterModule.forRoot(routes, {useHash: true})], exports: [RouterModule] })

而不是

@NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] })

我们的 Angular 5 购物车也是一个 Angular 5 移动应用程序,可导入到 XCODE (iPhone) 或 Android Studio 中。我们的默认构建文件夹,即 projectFolder/dist/,将适用于我们的生产版本,如果我们也希望它作为移动应用程序运行。要创建我们的生产构建,我们需要使用一些额外的命令。

我们使用文件夹名称 "www",这样我就可以将其用作移动应用程序和基于 Web 的应用程序,但您可以在生产构建后将其更改为任何名称,然后将其粘贴到您的网站中。

让我们使用以下命令创建 Angular 5 购物车的生产版本。

// Run in command line when directory is projectFolder
// flag prod bundle for production & flag aot enables the
// ahead-of-time compilation also known as offline compilation.
// --prod is now the same as --prod --aot
ng build --prod --base-href /$ROOT/Angular/cart-app/www/

在上面的路径中,您会注意到我在我的“C”盘上使用了文件夹“Angular2”,并在该目录中创建了我的“cart-app”文件夹。如果您的项目在不同的文件夹中,请相应调整上述路径。生成的“www”文件夹的内容将进入我们 Android Studio 或 XCODE 中的“www”文件夹,以便将 Angular 5 购物 Cart 用作移动应用程序,并且所有路径实际上都将正常工作。瞧!

部署到 IIS7 和其他服务器

我仍然使用 IIS 7,在 IIS 7 及更高版本上,您必须确保为我们的 json 文件设置 MIME 类型。我们的 Angular 5 购物车使用 config.json 和 products.json,它们要求在 IIS 7 或任何服务器上设置正确的 MIME 类型。默认情况下,IIS 7 或任何 IIS 均未配置为处理 .json 扩展名。因此,下面是一种非常简单的方法。您可以将此方法应用于 IIS 的根目录,以便 IIS 中的每个站点或虚拟文件夹都可以处理 .json,或者仅应用于特定站点。

  1. 打开 IIS 管理器
  2. 显示 IIS 服务器属性
  3. 单击 MIME 类型,然后添加 JSON 扩展名
    • 文件名扩展名:.json
    • MIME 类型:application/json
  4. 返回 IIS 服务器属性
  5. 点击 处理程序映射
    • 添加脚本映射
    • 请求路径:*.json
    • 可执行文件:C:\WINDOWS\system32\inetsrv\asp.dll
    • 名称:JSON

我们 Angular 5 电视购物车中的路由

我们的应用程序中只有几个简单的视图,即商店、产品、结账和空白。您可以轻松添加更多视图,如法律声明、服务条款、退款政策、如果您用作移动应用程序的 Cordova 或 PhoneGap 等。BlankComponent 用作某些路由调用的弥补。

const routes: Routes = [
    { path: '', component: StoreComponent },
    { path: 'store', component: StoreComponent },
    { path: 'cart', component: CartComponent },
    { path: 'product/:id', component: ProductComponent },
    { path: 'blank', component: BlankComponent }
];

在 Angular 5 中使用 APP_INITIALIZER 在应用程序启动之前读取数据

我们希望所有视图都能轻松访问我们的配置产品数据,因为一旦加载,这些数据不会改变。为此,我们在 app.module.ts 文件中添加以下内容。

// IN OUR APP.MODDULE.TS FILE...

import { NgModule } from '@angular/core';
import { APP_INITIALIZER } from '@angular/core';
// Other imports for our Modules...
import { Injectable } from '@angular/core';
import { Http, Jsonp } from "@angular/http";
// Too many files inside Rx folder causes delay in loading 
// so we don't load all of them to improve loading time.
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { ConfigService} from './services/config.service';

// We are Using AOT, So useFactory Can't be a Dynamic Function. 
// We MUST Use An EXPORTED function as shown below. 
export function initConfig(config: ConfigService){
    return () => config.load();
}

@NgModule({
  declarations: [
    AppComponent,
    NavbarComponent,
    BlankComponent,
    StoreComponent,
    CartComponent,
    ProductComponent,
    CapitalizePipe,
    UniquePipe,
    OrderByPipe,
    SafeHtmlPipe
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    FormsModule,
    JsonpModule,
    AppRoutingModule
  ],
  providers: [
    LocalStorageService, 
    DataObservableService, 
    PagerService, 
    OrderByPipe, 
    SafeHtmlPipe,
    ConfigService,
    {
        provide: APP_INITIALIZER,
        useFactory: initConfig,
        deps: [ConfigService],
        // If you use Jsop then also pass in Http & Jsonp 
        // deps: [ConfigService, Http, Jsonp],
        multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

在我们的 config.service.ts 文件中,我们将检索 JSON 配置数据和产品数据。我们将结合使用 Promise 和 Observable 以获得最佳结果。

Promise - Promise 处理异步操作完成或失败时的一个事件。

Observable - Observable 类似于流,允许您传递零个或多个事件,并且每次事件发生时都会调用回调。Observable 比 Promise 更受青睐,因为它提供了 Promise 的功能以及更多功能。使用 Observable,您是想处理零个事件、一个事件还是多个事件都无关紧要。在每种情况下您都可以使用相同的 API。

如下所示,这是我们的 config.service 文件,我们将使用 Promise 加载我们的 Config.json 文件,然后我们将读取 DATA_SOURCE 以查看使用哪种方法加载我们的 Products.json 文件。

// THIS IS OUR CONFIG.SERVICE.TS FILE
import { Inject, Injectable } from '@angular/core';
import { Http, Jsonp, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
import { DomSanitizer, SafeResourceUrl, SafeHtml, SafeUrl, SafeStyle} from '@angular/platform-browser';
import { Observable } from 'rxjs/Observable';
// Too many files inside Rx folder. So I did this to improve loading time.
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Config } from '../services/config.static';

@Injectable()
export class ConfigService {

    // Load configuration data so they will be available to all views
    private static _config: Object = null;
    // Load products so they will be available to all views
    // We can read from _promise value of DATA_SOURCE to determine 
    // what method to use, local or remote, to get Products Data.
    private static _products: Object = null;
    private static _promise: Promise = null;
    private retryCount = 2;
    headers: Headers;
    options: RequestOptions;

    constructor(private http: Http,
                private _jsonp: Jsonp,
                private sanitizer: DomSanitizer) {
        this.headers = new Headers(
            {
                'Content-Type': 'application/json',
                'Accept': 'q=0.8;application/json;q=0.9',
                'async': true,
                'dataType': 'jsonp'
            }); 
        this.options = new RequestOptions({ headers: this.headers });
        ConfigService._promise = this.load();
    }

    public config(): any { return ConfigService._config; }
    public getProducts(): any { return ConfigService._products; }
    public configKey(key: any) { return ConfigService._config[key] }
    getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }

    load() {
        let local_base = './assets/data/' + 'config' + '.json?';  
        // we add a random value to prevent caching - this trick works nicely!
        let local_rnd = 'rnd=' + this.getRandomInt(1, 500);
        let local_url = local_base + local_rnd;
        return new Promise((resolve, reject) => {
            this.http.get(local_url)
                .map((response: Response) => response.json())
                .catch((error: any) => {
                    console.error(error);
                    return Observable.throw(error.json().error || 'Server error');
                })
                .subscribe((data) => {
                    ConfigService._config = data;
                    // resolve(true); // UNSLASH THIS IF YOU DON'T GET PRODUCTS HERE !!!
                    // INCLUDE THIS IF YOU WANT TO RETRIEVE PRODUCTS HERE ////
                    let request: any = null;
                    switch (data.DATA_SOURCE) {
                        case 'local': {
                            local_base = './assets/data/' + 'products' + '.json?'; 
                            local_rnd = 'rnd=' + this.getRandomInt(1, 500);
                            local_url = local_base + local_rnd;
                            request = this.http.get(local_url);
                        } break;
                        case 'remote': {
                            // THIS IS AN EXAMPLE OF HOW TO USE A JSONP SERVER
                            let _store = '';
                            let _userid = '';
                            const jsonp_base = data.JSONP_DOMAIN1;
                            let jsonp_param = 'store=' + _store +  '&userid=' + _userid;
                            jsonp_param = jsonp_param + '&methodName=Feeds&jsonp=JSONP_CALLBACK';
                            let jsonp_rnd = '&rnd=' + this.getRandomInt(1, 500);
                            let jsonp_url = jsonp_base + jsonp_param + jsonp_rnd;
                            request = this._jsonp.get(jsonp_url, this.options);
                        } break;
                        case 'default': {
                            console.error('Environment file is not set or invalid');
                            resolve(true);
                        } break;
                    }
                    if (request) {
                        request
                            // .retry(this.retryCount) Deprecated in Angular 5
                            .map( (res) => {
                                let products = res.json();
                                this.checkProducts(products);
                                return products;
                            })
                            .catch((error: any) => {
                                console.error('Error reading ' + data.DATA_SOURCE + ' configuration file');
                            })
                            .subscribe((responseData) => {
                                ConfigService._products = responseData;
                                resolve(true);
                            });
                    } else {
                        console.error('Env config file "env.json" is not valid');
                        resolve(true);
                    }
                });
        });
    }

    checkProducts(prods: any) {
        if (prods) {
            prods.forEach((data) => {
                // Get embed format for given tube servers like youtube, vimeo, youku, etc.
                data.link  = this.getVideoEmbed(data.tube, data.videoid);
                data.videopage = this.sanitizer.bypassSecurityTrustResourceUrl(data.link);
            });
        };
    }
    // ... ETC.
}

有些人可能在使 JSONP 工作时遇到麻烦,所以我将解释您需要了解的一些事情。您可以使用几行 PHP 代码在服务器上轻松运行 JSONP 服务器,或者您可以使用 C# .NET 等。我为我的 JSONP 服务器使用的设计概念是,我决定使用一个带有工厂设计模式的通用处理程序,而不是使用多个通用处理程序或一个带有大量 switch/if 语句的处理程序。工厂根据传递的方法名返回一个类,该类仅用于处理该请求。工厂从 web.config 文件中读取方法名及其类并实例化处理程序。通用处理程序向工厂请求处理程序并执行一些预处理/后处理。这里有一个我写的关于使用 C# .NET 创建 JSONP 视频和电视广告服务器的文章链接,我用它来测试这个 Angular 5 购物车应用程序中的 JSONP 代码。

您可以下载我的 JSONP 服务器,用于从数百个视频服务器流式传输视频、电影、电视节目、频道和电视广告

C# .NET JSONP 服务器

大多数人在正确获取 URL 的这部分时会遇到问题

&methodName=Feeds&jsonp=JSONP_CALLBACK'

查看上面一行中的“jsonp”——这些字母由您的 JSONP 服务器决定,并且会因服务器而异。在我的 C# JSONP 服务器中,我使用了“jsonp”,但您在其他服务器中也会看到“callback”或只是“c”,但它的值取决于服务器。换句话说,不要只使用您在文章中常见的“callback”之类的东西,而是检查您正在连接的 JSONP 服务器需要什么。

使用我们预加载的配置和产品数据

现在,在我们的任何视图中检索配置和产品数据都变得轻而易举,如下所示。

this.config = this.configService.config();
// alert('Configurations: '+ JSON.stringify(this.config));


this.products = this.configService.getProducts();
// alert('Configurations: '+ JSON.stringify(this.products));

我添加了一个名为 config.static 的文件,以说明另一种可能更好的全局配置文件方法。使用这种方法如下所示。

import { Config } from 'app/services/config.static';
alert(Config.CONFIG.STORE_BG_IMAGES[0]);

我们的 Angular 5 滑动按钮分页

您可以在下面看到我们的 PagerService 按钮。

我们的分页器实际上相当简单,其代码如下。

<table style="float:right;">
    <tr><td>
        <!-- slide button pager -->
        <ul *ngIf="pager.pages && pager.pages.length" class="pagination">
            <li [ngClass]="{disabled:pager.currentPage === 1}">
                <a (click)="setPage(1)">First</a>
            </li>
            <li [ngClass]="{disabled:pager.currentPage === 1}">
                <a (click)="setPage(pager.currentPage - 1)">Previous{{page}}</a>
            </<li>
            <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
                <a (click)="setPage(pager.currentPage + 1)">Next</a>
            </<li>
            <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
                <a (click)="setPage(pager.totalPages)">Last</a>
            </<li>
        </<ul>
    </<td></<tr>
</table>

在 Angular 5 中播放嵌入视频

在我们的应用程序中,我们从数百个允许在网页中嵌入的视频服务器中检索视频。除了显示数百万部电影和各种视频,此代码还将显示您在这些视频服务器(如 YouTube)上获得的盈利视频,这些视频包含在电影和其他视频中。在我们的 ConfigService 中,我们在 checkProducts 中应用了各种视频服务器的嵌入格式,如下所示。

checkProducts(prods: Product[]) {
    if (prods) {
        prods.forEach((data) => {
            // Get embed format for tube servers like youtube, vimeo, youku, etc.
            data.link  = this.getVideoEmbed(data.tube, data.videoid);
            data.videopage = this.sanitizer.bypassSecurityTrustResourceUrl(data.link);
        });
    };
}

Angular 5 产品视图

此视图显示了产品的更多详细信息,并允许用户添加或从购物车中移除产品,并显示购物车中已添加的产品数量。您可以显示产品的视频或图片。如果显示产品图片,则单击图片会弹出一个对话框,显示图片的更大视图。您可以在下面看到显示图片的产品视图。

产品模块使用 ConfigService 获取产品数据,然后选择路由器传递的任何“id”。

// private route: ActivatedRoute 
// get URL parameters via Route
this.sub = this.route
    .params
    .subscribe(params => {
    this.params = params['id'];
    this.getProducts();
});

getProducts() {
    this.prods = (this.configService.getProducts()).filter(prods => 
        ((prods.sku === this.params) || (this.params === '')) );
    window.scrollTo(0, 0);
}

Angular 5 购物车视图

我们的 CartModule View 调用 cart.service.ts 中的 CartService,它使用 localStorage 上的 Observable,如下所示。

loadItems(): Observable {
    let items = localStorage != null ? localStorage[this.cartName + '_items'] : null;
    if (items != null && JSON != null) {
        try {
            items = JSON.parse(items);
            for (let i = 0; i < items.length; i++) {
                let item = items[i];
                if (item.sku != null && item.productname != null && item.unitprice != null 
                    && item.saleprice != null && item.showsale != null 
                    && item.quantity != null && item.sh != null && item.faux != null) {
                    item = new this.cartItem(item.sku, item.productname, item.unitprice, 
                        item.saleprice, item.showsale, item.quantity, item.sh, item.faux);
                    this.items.push(item);
                }
            }
        }
        catch (err) {
            // ignore errors while loading...
        }
    }
    return items;
}

用户可以使用 PayPal、Google Wallet 和 Stripe 编辑购物车并结账。以下是在笔记本电脑上购物车视图的样子。

  1. PayPal。此付款方式指定用于付款的商家账户或 BuyNow 账户(非商家账户)。要使用 PayPal,您必须创建 BuyNow 账户或 PayPal 商家账户。您可以在此处创建:https://www.paypal.com/webapps/mpp/merchantaypal.com/webapps/mpp/merchant
  2. Google Wallet。此支付方式要求您在 Google 创建商家账户。您可以在此处完成:https://developers.google.com/commerce/wallet/digital/training/getting-started/merchant-setup
  3. Stripe。此支付方式允许您在网站上嵌入其 API 以接受付款,而无需获取商家账户。Stripe 没有设置费、月费、最低收费、验证费、卡存储费或失败付款费。Stripe 有一个 7 天的交易等待期,以便 Stripe 可以分析相关业务并检测欺诈行为。https://stripe.com

正如我之前解释的,您可以将编译后的文件用作可以在任何移动设备上安装的移动购物车,或者用作您网站上的基于网络的 Angular 5 购物车

左边显示的是我在手机上使用它来收集漫画书。

最好的功能是,我可以在我的 Config.json 文件中设置一个 DISTRIBUTER_ID,然后将带有此应用程序的链接或文件夹提供给想要销售我的产品并获得佣金的人。

非常酷的用户界面和悬停效果

首先,我想要包含一个 Pinterest 风格的布局,所以我决定使用一个我在购物车中经常看到的常用布局,即 Codrops 著名的 ViewModeSwitch,您可以在以下网址找到它:https://github.com/codrops/ViewModeSwitchViewModeSwitch 是一个 CSS Pinterest 风格的布局,在许多商业购物中都有使用,并且与 AngularJS 配合良好,只需进行少量更改。

我决定添加一组悬停动画,我编写了一个动画编辑器,它在菜单中,用于选择并将不同的悬停动画应用到购物车中的不同对象。我查看了一些悬停库,并选择了一个我非常喜欢的由 Ian Lunn 编写的名为 Hover 的库,您可以在他的 GitHub 上探索它:https://github.com/IanLunn

要应用效果,只需在菜单中选择“效果”选项卡,然后选择一个绿色单选按钮,即:storeimg、store pill、carousel img 或 carousel pill。请注意,只有在您添加了 Super Slick Carousel 的 JavaScript 后,轮播选项才可用。选择要应用悬停效果的对象后,只需单击下方列表中的所需效果。您可以轻松定义新对象以在视图中应用这些效果。

Hover 库中的悬停效果应用如下

  changeAnimation(effect_name) {
    event.preventDefault(); 
    this.isOpenNavbarAnimation = !this.isOpenNavbarAnimation;
    let e = '';
    if (this.myModel === 'carousel_img_video') {
        e = '.carousel_img_video';
    } else if (this.myModel === 'carousel_pill') {
        e = '.carousel_pill';
    } else if (this.myModel === 'store_img_video') {
        e = '.store_img_video';
    } else if (this.myModel === 'store_pill') {
        //e = '.nav-pills li';
        e = '.store_pill';
    }
    if (e.length > 0) {
        $(e).removeClass(function (index, css) {
            return (css.match(/(^|\s)hvr-\S+/g) || []).join(' ');
        });
        $(e).addClass(effect_name);
    }
    if (effect_name.length > 0) {
        $(e).removeClass(function (index, css) {
            return (css.match(/(^|\s)hvr-\S+/g) || []).join(' ');
        });
        $(e).addClass(effect_name);
    }
  };

以下控件设置上述效果:

  // create a radioButtonGroup for our apply effects options
  public myOptions = [
      { id: 'store_img_video', name: 'store img', disabled: false, showinfo: '' },
      { id: 'store_pill', name: 'store pill', disabled: false, showinfo: '' },
      { id: 'carousel_img_video', name: 'carousel img', disabled: false, showinfo: '' },
      { id: 'carousel_pill', name: 'carousel pill', disabled: false, showinfo: '' }
  ];

Bootstrap 3 导航栏

我使用了 Bootstrap 3,但没有使用 ui.bootstrap,因为 ui.bootstrap 让我头疼,难以跟上他们的变化。Bootstrap 3 拥有 navbars,可以轻松地在您的应用程序内部使用 AngularJS 更改导航栏的外观,如下面的购物车中所示。为了在这些导航栏中创建渐变,我使用了以下网址的渐变编辑器:http://www.colorzilla.com/gradient-editor/

对于导航栏,我应用了与导航栏颜色协调,以便每个导航栏在悬停在由 Codrops 著名的 ViewModeSwitch 创建的胶囊上时都有自己的悬停效果。更改背景颜色和放大图像以及数十种其他酷炫悬停效果的代码使用 Hover 库应用。一些其他过渡效果来自 Codrops 上与 ViewModeSwitch 相关的项目,名为 ResponsiveIconGrid,位于:

http://tympanus.net/Blueprints/ResponsiveIconGrid/#

在每个导航栏样式表中,我们都有以下用于胶囊的悬停渐变 CSS。

这为每个导航栏产生了不同的悬停效果。但是,当购物车在移动设备上时,我们需要关闭许多这些效果,这个项目中的 CSS 正是这样做的,以便在移动设备上获得更好的显示效果。Codrops 上提供了数十种各种动画效果的 Codrops 著名 ViewModeSwitch 样本。但是请记住,动画效果会分散注意力,将读者的注意力从您的产品广告文案中移开,因此请谨慎使用。您可以在下面看到有大量效果可以应用于任何视图中的任何对象。选项卡菜单下拉菜单中的红色按钮允许您删除已应用的任何悬停效果。

更多字形图标请查看

http://glyphicons.bootstrapcheatsheets.com/

您必须决定的事情之一是如何处理在菜单外点击时关闭展开的下拉菜单。我尝试了几种方法,最后决定采用以下方法来处理菜单外点击以关闭 NavbarComponent 中任何展开的下拉菜单,如下所示。

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss'],
  host: {
    '(document:click)': 'offNavClick($event)',
  },
  providers: [WindowService, DataObservableService, LocalStorageService, CartService]
})

  constructor(private _eref: ElementRef) { }

  offNavClick(event) {
    // Off menu code to close dropdowns
    if (!this._eref.nativeElement.contains(event.target)) {
      this.isOpenNavbarTheme = false;
      this.isOpenNavbarAnimation = false;
      this.isOpenNavbarVideoSites = false;
    }
  }

Bootstrap 3 渐变按钮

我不喜欢 Bootstrap 3 按钮的外观,所以我决定给它们一些深度,如下所示。为此,我使用了一个非常酷的 Bootstrap 3 编辑器,它通过单个 CSS 代码块创建具有渐变、鼠标悬停和鼠标按下效果的按钮,网址为:http://charliepark.org/bootstrap_buttons/

为您的 Angular 5 电视购物车应用程序添加功能

您可以使用 ng generate 命令向应用程序添加功能,方法是转到要添加模块、服务等的目录,并使用以下命令之一

  • ng generate class my-new: 向您的应用程序添加一个类
  • ng generate component my-new: 向您的应用程序添加一个组件
  • ng generate directive my-new: 向您的应用程序添加一个指令
  • ng generate enum my-new: 向您的应用程序添加一个枚举
  • ng generate module my-new: 向您的应用程序添加一个模块
  • ng generate pipe my-new: 向您的应用程序添加一个管道
  • ng generate service my-new: 向您的应用程序添加一个服务

例如,要添加一个购物车服务,您可以进入要添加它的目录并输入

C:\Angular2\cart-app\cd src\app\services
C:\Angular2\cart-app\src\app\services>ng generate service cart

结论

我也喜欢 Bootstrap,因为它使得创建有吸引力的、响应式的 HTML 布局变得容易。除了漂亮的一组样式和图标,Bootstrap 还提供了一些 JavaScript 组件,您可以使用它们来增强您的 UI,例如工具提示、弹出框、菜单等。您可以在这里了解 Bootstraphttp://twitter.github.io/bootstrap/

 

© . All rights reserved.