如何构建无服务器,CMS支持的Angular应用程序
角已经起飞的普及和被广泛应用。 由谷歌工程师开发和维护,角发现跨所有动态Web应用程序的地方,是一个越来越有需求的平台。角度提供了大量热情的社区和优秀的MVC不需要开发者花费宝贵的时间编写代码来重新结合在一起将多个MVC组件的优势。 总之,角是前端开发一个强大的和全面的Web应用程序框架,单元测试准备,使其成为首选的工具,许多开发商。如果您使用的角度,你可能会碰到需要内容管理功能 - 一...
Angular已迅速普及并得到广泛使用。 Angular由Google工程师开发和维护,已经在动态Web应用程序中找到了自己的位置,并且是一个越来越受欢迎的平台。
Angular具有庞大而热情的社区和出色的MVC的优点,它们不需要开发人员花费宝贵的时间编写代码来将多个MVC组件重新组合在一起。 简而言之,Angular是用于前端开发的健壮且全面的Web应用程序框架,它已经进行了单元测试,使其成为许多开发人员的首选工具。
如果您使用的是Angular,则可能会遇到对内容管理功能的需求-博客就是一个例子。 在Angular应用中添加CMS似乎令人望而生畏,特别是如果您试图将其集成到WordPress之类的传统CMS中时,但是基于API的CMS新品种极大地简化了事情。 ButterCMS是基于SaaS的无头CMS的一个示例,它提供了托管的CMS仪表板和内容API,您可以从Angular应用程序中查询它们。 这意味着您无需启动任何新的基础架构即可将CMS添加到Angular应用中。
本教程将演示如何构建由CMS驱动的Angular应用程序,该应用程序具有通过API提供支持的营销页面(客户案例研究),博客和常见问题解答。 无需服务器!
安装
首先,您将开始安装Angular CLI。
npm install -g @angular/cli</td>
使用Angular CLI设置一个新的Angular项目。 默认情况下,Angular CLI使用CSS样式,因此添加--style=scss
标志可--style=scss
Angular CLI改为使用SCSS:
ng new hello-buttercms-project --style=scss
cd hello-buttercms-project
安装Angular Material和Angular Material相关的软件包:
npm install --save @angular/material @angular/cdk
npm install --save @angular/animations
安装ButterCMS。 在命令行中运行以下命令:
npm install buttercms --save
也可以使用CDN加载黄油:
<script src="https://cdnjs.buttercms.com/buttercms-1.1.1.min.js"></script>
快速入门
在您选择的代码编辑器中打开项目。 在src/app
创建一个名为_services
的目录。
我们创建一个名为butterCMS.service.js
的文件。 这使我们可以将您的API令牌放在一个位置,而不会意外更改它。
import * as Butter from 'buttercms';
export const butterService = Butter('b60a008584313ed21803780bc9208557b3b49fbb');
您可以将此文件导入到我们要使用ButterCMS的任何组件中。
对于快速入门,请转到src/app/hello-you/hello-you.component.ts
并导入butterService
:
import {butterService} from '../_services';
在HelloYouComponent
内部创建方法:
fetchPosts() {
butter.post.list({
page: 1,
page_size: 10
})
.then((res) => {
console.log('Content from ButterCMS')
console.log(res)
})
}
现在,通过将组件添加到OnInit
生命周期挂钩中来在加载组件时调用此方法:
ngOnInit() {
this.fetchPosts();
}
该API请求会提取您的博客文章。 您的帐户附带一个示例帖子,您将在回复中看到该帖子。
接下来,创建另一种方法来检索“首页标题内容”字段:
fetchHeadline() {
butter.content.retrieve(['homepage_headline'])
.then((res) => {
console.log('Headline from ButterCMS')
console.log(res)
})
}
将此方法添加到OnInit
生命周期挂钩。
ngOnInit() {
this.fetchPosts();
this.fetchHeadline();
}
此API请求获取首页标题内容。 您可以设置自己的自定义内容字段来管理所需的任何种类的内容。
添加营销页面
设置CMS支持的页面是一个简单的三步过程:
- 定义页面类型
- 创建一个页面
- 集成到您的应用程序
定义页面
首先,创建一个页面类型来表示您的客户案例研究页面。 接下来,定义客户案例研究所需的字段。 定义页面类型后,您现在可以创建第一个案例研究页面。 指定页面的名称和URL,然后填充页面的内容。
定义页面后,ButterCMS API将以JSON格式返回它,如下所示:
{
"data": {
"slug": "acme-co",
"fields": {
"facebook_open_graph_title": "Acme Co loves ButterCMS",
"seo_title": "Acme Co Customer Case Study",
"headline": "Acme Co saved 200% on Anvil costs with ButterCMS",
"testimonial": "<p>We've been able to make anvils faster than ever before! - <em>Chief Anvil Maker</em></p>\r\n<p><img src=\"https://cdn.buttercms.com/NiA3IIP3Ssurz5eNJ15a\" alt=\"\" caption=\"false\" width=\"249\" height=\"249\" /></p>",
"customer_logo": "https://cdn.buttercms.com/c8oSTGcwQDC5I58km5WV",
}
}
}
本指南使用Angular框架和Angular CLI生成我们所有的组件并打包我们的应用程序。
让我们看一下代码。
创建一个新项目
ng new buttercms-project --style=scss
cd buttercms-project
npm install --save @angular/material @angular/cdk
npm install --save @angular/animations
npm install -S buttercms
ng serve
您的localhost:4200应该已经准备好服务您的Angular页面了。
创建TypeScript以导出ButterCMS服务
在src/app
,创建一个名为_services
的目录。 创建一个名为butterCMS.service.js
的文件。
import * as Butter from 'buttercms';
export const butterService = Butter('your_api_token');
更新组件路由
这些组件由Angular CLI使用以下命令生成:
ng g component <my-new-component>
在src/app
,创建一个名为app-routing.module.ts
的文件:
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {CustomerComponent} from './customer/listing/customer.listing.component';
import {FaqComponent} from './faq/faq.component';
import {BlogPostComponent} from './blog-post/listing/blog-post.component';
import {HomeComponent} from './home/home.component';
import {CustomerDetailsComponent} from './customer/details/customer.details.component';
import {BlogPostDetailsComponent} from './blog-post/details/blog-post.details.component';
import {FeedComponent} from './feed/feed.component';
import {HelloYouComponent} from './hello-you/hello-you.component';
const appRoutes: Routes = [
{path: 'customer', component: CustomerComponent},
{path: 'customer/:slug', component: CustomerDetailsComponent},
{path: 'faq', component: FaqComponent},
{path: 'blog', component: BlogPostComponent},
{path: 'blog/:slug', component: BlogPostDetailsComponent},
{path: 'rss', component: FeedComponent},
{path: 'hello-you', component: HelloYouComponent},
{path: 'home', component: HomeComponent},
{path: '**', redirectTo: 'home'}
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
设置客户列表页面
在apps/customer
类型下:
ng g component listing
在文件apps/customer/listing/customer.listing.component.ts
:
- 进口
butterService
- 在
OnInit
挂钩中,使用butterService
获取客户列表 - 将结果存储在pages变量中,标记(HTML)将使用数据进行更新。
import {Component, OnInit} from '@angular/core';
import {butterService} from '../../_services';
@Component({
selector: 'app-customer',
templateUrl: './customer.listing.component.html',
styleUrls: ['./customer.listing.component.scss']
})
export class CustomerComponent implements OnInit {
public pages: any[];
constructor() { }
ngOnInit() {
butterService.page.list('customer_case_study')
.then((res) => {
this.pages = res.data.data;
});
}
}
在customer.listing.component.html
显示结果:
<mat-card>
<mat-card-title class="page-title">Customers</mat-card-title>
<mat-divider></mat-divider>
<mat-card-content class="page-body">
<mat-card *ngFor="let page of pages">
<mat-card-title>
<div class="container">
<a [routerLink]="[page.slug]">
<div fxLayout="row" fxLayout.xs="column"
fxFlex class="content">
<div class="blocks">
<img src="{{page.fields.customer_logo}}" alt="{{page.fields.seotitle}}" height="64"
width="64"/>
</div>
<div class="blocks">
{{page.fields.headline}}
</div>
</div>
</a>
</div>
</mat-card-title>
</mat-card>
</mat-card-content>
<mat-divider></mat-divider>
<mat-card-footer>
<div class="page-footer">
<mat-icon>whatshot</mat-icon>
</div>
</mat-card-footer>
</mat-card>
设置客户详细信息页面
在apps/customer
,输入ng g component details
。
apps/customer/details/customer.details.component.ts
创建客户页面
- 进口
butterService
- 在
OnInit
钩子中,使用butterService
来获取URL路径中给出了错误信息的客户页面 - 将结果存储在页面变量中,标记(HTML)将使用客户数据进行更新。
import {Component, OnInit} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {ActivatedRoute} from '@angular/router';
import {butterService} from '../../_services';
import {map, take} from 'rxjs/operators';
@Component({
selector: 'app-customer-details',
templateUrl: './customer.details.component.html',
styleUrls: ['./customer.details.component.scss']
})
export class CustomerDetailsComponent implements OnInit {
constructor(protected route: ActivatedRoute) { }
protected slug$: Observable<string>;
public page: any;
ngOnInit() {
this.slug$ = this.route.paramMap
.pipe(
map(params => (params.get('slug')))
);
this.slug$.pipe(
take(1))
.subscribe(slug => {
butterService.page.retrieve('customer_case_study', slug)
.then((res) => {
this.page = res.data.data;
}).catch((res) => {
console.log(res);
});
});
}
}
将结果显示在customer.details.component.html
。
<mat-card>
<div class="container">
<div fxLayout="column" class="details">
<div class="blocks">
<img src="{{page.fields.customer_logo}}" alt="" height="124" width="124"/>
</div>
<h1 class="blocks">
{{page.fields.headline}}
</h1>
<h3 class="is-size-3">Testimonials</h3>
<div [innerHTML]="page.fields.testimonial"></div>
<div [innerHTML]="page.fields.body"></div>
</div>
</div>
</mat-card>
现在,您可以通过所有“客户页面”列表或直接通过URL导航到“客户页面”。
添加知识库
设置内容字段
假设您想将CMS添加到带有标题和带有答案的问题列表的静态FAQ页面。
使用Butter使您的内容动态化是一个两步过程:
- 在Butter中设置自定义内容字段
- 将字段集成到您的应用程序中。
要设置自定义内容字段,请首先登录Butter仪表板。
创建一个新的工作区或单击一个现有的工作区。 通过工作区,您可以以友好的方式为内容编辑者组织内容字段,并且对开发或API没有影响。 例如,一个房地产网站可能有一个名为Properties的工作区,另一个名为About Page 。
一旦进入工作区,请单击按钮以创建新的内容字段。 选择对象类型,然后将字段命名为FAQ Headline。
保存后,添加另一个字段,但是这次选择“ 收集”类型,并将字段命名为FAQ Items 。
在下一个屏幕上,为集合中的项目设置两个属性。
现在返回您的工作区并更新标题和常见问题解答。
整合您的应用
创建常见问题解答组件
在apps
,键入ng g component faq
。
apps/faq/faq.component.ts
设置onInit挂钩以加载常见问题
import {Component, OnInit} from '@angular/core';
import {butterService} from '../_services';
@Component({
selector: 'app-faq',
templateUrl: './faq.component.html',
styleUrls: ['./faq.component.scss']
})
export class FaqComponent implements OnInit {
constructor() {}
public faq: any = {
items: [],
title: 'FAQ'
};
ngOnInit() {
butterService.content.retrieve(['faq_headline', 'faq_items'])
.then((res) => {
console.log(res.data.data);
this.faq.title = res.data.data.faq_headline;
this.faq.items = res.data.data.faq_items;
});
}
}
显示结果
<mat-card>
<mat-card-title class="page-title"></mat-card-title>
<mat-divider></mat-divider>
<mat-card-content class="page-body">
<mat-card *ngFor="let item of faq.items">
<mat-card-content>
<h3>
{{item.question}}
</h3>
<div>
{{item.answer}}
</div>
</mat-card-content>
</mat-card>
</mat-card-content>
<mat-divider></mat-divider>
<mat-card-footer>
<div class="page-footer">
<mat-icon>whatshot</mat-icon>
</div>
</mat-card-footer>
</mat-card>
在黄油仪表盘中输入的值将立即更新我们应用程序中的内容。
写博客
为了显示帖子,我们在您的应用中创建一个简单的/blog
路由,并从Butter API中获取博客帖子,以及一个/blog/:slug
路由来处理各个帖子。
请参阅我们的API参考以获取其他选项,例如按类别或作者过滤。 响应中还包含一些我们将用于分页的元数据。
设置博客主页
在apps/blog-post
,输入ng g component listing
。
apps/blog-post/listing/blog-post.listing.component.ts
更新组件以获取所有帖子:
- 进口
butterService
- 在Init上获取所有帖子
import {Component, OnInit} from '@angular/core';
import {butterService} from '../../_services';
@Component({
selector: 'app-blog-post',
templateUrl: './blog-post.component.html',
styleUrls: ['./blog-post.component.scss']
})
export class BlogPostComponent implements OnInit {
public posts: any[];
constructor() { }
ngOnInit() {
butterService.post.list({
page: 1,
page_size: 10
}).then((res) => {
console.log(res.data)
this.posts = res.data.data;
});
}
}
显示结果:
<mat-card>
<mat-card-title class="page-title">Blog Posts</mat-card-title>
<mat-divider></mat-divider>
<mat-card-content class="page-body">
<mat-card *ngFor="let post of posts">
<mat-card-title>
<a [routerLink]="[post.slug]">
<div class="container">
<div fxLayout="row" fxLayout.xs="column"
fxFlex class="content">
<div class="blocks">
<img *ngIf="post.featured_image" src="{{post.featured_image}}" height="64" width="64"/>
</div>
<div class="blocks">
{{post.title}}
</div>
</div>
</div>
<div class="container">
<div fxLayout="column" class="summary">
<div [innerHTML]="post.summary"></div>
</div>
</div>
</a>
</mat-card-title>
</mat-card>
</mat-card-content>
<mat-divider></mat-divider>
<mat-card-footer>
<div class="page-footer">
<mat-icon>whatshot</mat-icon>
</div>
</mat-card-footer>
</mat-card>
设置博客文章页面
在apps/blog-post
,输入ng g component details
。
apps/blog-post/details/blog-post.details.component.ts
显示单个帖子:
- 进口
butterService
- 在
OnInit
挂钩中,使用butterService
获取URL路径中给出了段名的博客文章。 - 将结果存储在post变量中,标记(HTML)将使用客户数据进行更新。
import {Component, OnInit, ViewEncapsulation} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {ActivatedRoute} from '@angular/router';
import {butterService} from '../../_services';
import {map, take} from 'rxjs/operators';
@Component({
selector: 'app-blog-post-details',
templateUrl: './blog-post.details.component.html',
styleUrls: ['./blog-post.details.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class BlogPostDetailsComponent implements OnInit {
constructor(protected route: ActivatedRoute) {
}
protected slug$: Observable<string>;
public post = {
meta: null,
data: null
};
ngOnInit() {
this.slug$ = this.route.paramMap
.pipe(
map(params => (params.get('slug')))
);
this.slug$.pipe(
take(1))
.subscribe(slug => {
butterService.post.retrieve(slug)
.then((res) => {
this.post = res.data;
}).catch((res) => {
console.log(res);
});
});
}
}
显示结果:
<mat-card>
<div class="container">
<div fxLayout="column" class="blog-details">
<div class="container">
<div fxLayout="row">
<h1 class="blocks">
{{post.data.title}}
</h1>
<div *ngIf="post.meta.previous_post"><a [routerLink]="post.meta.previous_post"><</a></div>
<div *ngIf="post.meta.next_post"><a [routerLink]="post.meta.next_post">></a></div>
</div>
<h4>
{{post.data.author.first_name}} {{post.data.author.last_name}}
</h4>
<div class="post-body" [innerHTML]="post.data.body"></div>
</div>
</div>
</div>
</mat-card>
现在,您的应用程序具有一个可以正常运行的博客,可以在ButterCMS仪表板中轻松对其进行更新。
类别,标签和作者
使用Butter的API来分类,标记和作者,以显示和过滤博客中的内容。
列出所有类别并按类别获取帖子
在onInit()
生命周期挂钩上调用以下方法:
methods: {
...
getCategories() {
butter.category.list()
.then((res) => {
console.log('List of Categories:')
console.log(res.data.data)
})
},
getPostsByCategory() {
butter.category.retrieve('example-category', {
include: 'recent_posts'
})
.then((res) => {
console.log('Posts with specific category:')
console.log(res)
})
}
},
created() {
...
this.getCategories()
this.getPostsByCategory()
}
包起来
恭喜! 您已成功使用内容API将静态Angular应用程序转换为基于CMS的应用程序,从而维护了无服务器架构。 您的开发团队可以利用Angular节省时间的方面,并且通过使用无服务器CMS节省了更多时间。
From: https://www.sitepoint.com/how-to-build-a-serverless-cms-powered-angular-application/
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)