使用 Vue、Bulma 和 Airtable 构建作品集网站
离开全栈训练营已经三年了,这是我第一次需要搭建一个作品集网站。我想做一个相对简单、易于更新、并且随着时间的推移易于扩展和改进的网站。
这个教程完美吗?当然完美!这是我写的第一篇教程,而且我一直在自学 Vue,所以有些部分我肯定可以改进(如果你觉得有什么不同,请在评论区告诉我)。不过,我知道这篇文章可能会对某些人有所帮助!
您可以在 github 上看到我的整个投资组合的代码,这些代码是从这个起点创建的,网址为:https://github.com/markjohnson303/portfolio
完成的示例位于hellomark.dev,但这是一个正在进行的工作,您可能会看到一些与此处描述的不同之处。
工具
Vue.js:我选择 Vue 来做这个项目,是因为它是我最熟悉的框架。有人可能会说,对于像这样的小项目来说,它有点大材小用,对你来说可能确实如此。它对我来说很合适,因为它使用起来很顺手,而且足够灵活,足以应付我将来的各种需求。我也希望在下一个职位上使用它,所以何乐而不为呢!
Bulma:在这个项目之前我从未使用过 Bulma,但我希望它能让我快速上线网站,并随着时间的推移轻松改进样式。Bulma 易于学习,但易于构建。它没有世界上最大的组件库,但它的组件库构建得非常扎实。
Airtable:我一直想在一个项目中使用 Airtable。据 Airtable 介绍,它“一半是电子表格,一半是数据库”,设计灵活,适用于各种用途。我在这里将它用作内容管理系统 (CMS),因为它非常易于使用,并且拥有强大的 API 和完善的文档(可根据您的数据库进行定制)。现在它已经设置好了,我可以在整个网站上使用它来做各种有趣的事情。而且它是免费的!
入门
首先需要设置你的 Vue 项目。我们将使用 Vue CLI 来搭建项目。请确保你已经安装了 Vue 和 Vue CLI:
$ npm install -g vue
$ npm install -g @vue/cli
然后创建你的项目:$ vue create portfolio
然后启动它:$ npm run serve
Vue CLI 提供了一个非常有用的起点,其中包含我们需要的大量文件和文件夹。我们将以此为基础进行构建。
现在让我们添加我们的 CSS 框架 Bulma。$ npm install --s bulma
并将 Sass 样式表添加到我们的App.vue
文件中
<style lang="sass">
@import "~bulma/bulma.sass"
</style>
您可以在此处(导入上方)对 Bulma 默认值进行任何调整。
我们将安装 Axios(用于与我们的 Airtable API 配合使用)$ npm install --s axios
我们需要VueSimpleMarkdown,这样我们就可以用 markdown 撰写和设计我们的帖子。
$ npm install -s vue-simple-markdown
我们main.js
将输入:
import VueSimpleMarkdown from 'vue-simple-markdown'
import 'vue-simple-markdown/dist/vue-simple-markdown.css'
Vue.use(VueSimpleMarkdown)
设置我们的路线
我们将为该网站设置 5 个主要路由:关于、联系、主页、项目和项目。让我们在 In 中设置它们src/router.js
。
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import About from "./views/About.vue";
import Contacts from "./views/Contact.vue";
import Projects from "./views/Projects.vue"
import Project from "./views/Project.vue"
Vue.use(Router);
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/about",
name: "about",
component: About
},
{
path: "/contact",
name: "contact",
component: Contact
},
{
path: "/projects",
name: "projects",
component: Projects
},
{
path: "/project/:slug",
name: "project",
component: Project
}
]
});
}
奇怪的是path: "/project/:slug"
。稍后我们将使用此路线根据 slug 显示来自 Airtable 的单个项目。
我们还将为每个 创建一个空组件src/views
,例如这里Contact.vue
。我们稍后会填充它们。
<template>
<div>
</div>
</template>
<script>
export default {
name: "contact",
};
</script>
添加页眉和页脚
让我们添加页眉(带导航)和页脚,添加一些样式,并运用一些 Vue 的魔法,让它在移动设备上运行。我们将这段代码添加到App.vue
每个视图中,以便它能够显示出来。
<template>
<div id="app">
<meta name="viewport" content="width=device-width, initial-scale=1">
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<router-link class="navbar-item" to="/">
<img src="./assets/name-mark.jpg" width="112" height="28">
</router-link>
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample" :class="{ 'is-active': showNav }" @click="showNav = !showNav">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu" :class="{ 'is-active': showNav }">
<div class="navbar-start">
</div>
<div class="navbar-end">
<router-link to="/" class="navbar-item">
Home
</router-link>
<router-link to="/about" class="navbar-item">
About
</router-link>
<router-link to="/projects" class="navbar-item">
Projects
</router-link>
<router-link to="/contact" class="navbar-item">
Contact
</router-link>
</div>
</div>
</nav>
<router-view />
<footer class="footer">
<div class="content has-text-centered">
<p>
Built by Mark Johnson with Vue.js, Bulma, and Airtable.
</p>
</div>
</footer>
</div>
</template>
<script>
export default {
name: "App",
data() {
return{
showNav: false
}
},
};
</script>
<style type="text/css">
#app {
min-height: 100vh;
overflow: hidden;
display: block;
position: relative;
padding-bottom: 168px; /* height of your footer */
}
footer {
position: absolute;
bottom: 0;
width: 100%;
}
</style>
<style lang="sass">
@import "~bulma/bulma.sass"
</style>
静态页面
“关于”、“主页”和“联系”页面没有任何动态内容,您可以随意添加任何您喜欢的内容。例如,以下是我在主页上所做的。我在这里保持了简洁,但您可以根据自己的喜好进行修饰。
<template>
<div>
<div class="hero is-cover is-relative is-fullheight-with-navbar is-primary">
<div class="hero-body">
<div class="container">
<h1 class="title is-1">Hello, I'm Mark.</h1>
<h2 class="subtitle is-3">A customer focused, entrepreneurially minded web developer.</h2>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "home",
};
</script>
构建项目页面
项目页面开始变得有趣起来。我们将从 Airtable 中提取信息,并为每个项目显示一个摘要卡。
设置 Airtable
在 Airtable 上创建一个名为“项目”的新库。创建以下字段:“标题”(单行文本)、“slug”(单行文本)、“正文”(长文本)、“图片”(附件)、“发布日期”(日期)、“已发布”(复选框)、“摘录”(单行文本)。
瞧!一个简单的 CMS 就完成了!只需在其中填充几行虚拟数据,就能清楚地看到正在处理的内容。确保“slug”是唯一的!我们将在后续步骤中使用它来构建 URL。
构建用于展示项目的卡片
我们将创建一个组件来显示项目摘要。它可重复使用,以便您以后可以用它创建博客!
在src/components
新建一个文件,命名为PostCard.vue
。填写如下内容:
<template>
<div class="post-card">
<div class="card">
<div class="card-image">
<figure class="image is-square">
<img :src="image" alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-content">
<p class="title is-4">{{title}}</p>
<p class="subtitle is-6">{{date}}</p>
</div>
</div>
<div class="content">
<p>{{snippet}}</p>
<router-link :to="'/project/'+slug" class="button is-fullwidth">View Project</router-link>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "PostCard",
props: {
title: String,
date: String,
snippet: String,
image: String,
slug: String
}
};
</script>
从 Airtable 的 API 获取项目后,我们将从“项目”页面引入道具。它们会将内容和完整项目视图的链接填充到模板中。
创建服务来引入项目
让我们建立与 Airtable API 的连接。在 创建一个目录src/services
,并在其中放置一个名为 的文件ProjectsService.js
。
在项目服务中,我们将使用 Axios 调用 Airtable API 并获取所有项目。您的文件应如下所示:
import axios from 'axios'
const Axios = axios.create({
baseURL: "https://api.airtable.com/v0/[YOUR APP ID]/Projects"
});
Axios.defaults.headers.common = {'Authorization': `Bearer ` + process.env.VUE_APP_AIRTABLEKEY}
export default{
getProjects() {
return Axios.get()
}
}
您需要设置baseURL
Airtable 基础的 ID。您可以在 Airtable 的 URL 中找到它。
您还需要从 Airtable 添加您的 API 密钥。我将我的密钥放在.env.local
Vue 项目根目录中名为 的文件中。此文件已列在 .gitignore 中,因此您无需担心它被暴露。文件中的内容如下VUE_APP_AIRTABLEKEY=[YOUR API KEY]
:
最后,我们导出一个在 baseURL 中调用 API 端点的 get 函数。
显示项目卡
我们将在“项目”视图中显示项目的卡片。在您的Projects.vue
模板中:
<template>
<div>
<section class="hero is-medium is-primary is-bold">
<div class="hero-body">
<div class="container">
<h1 class="title is-2">
Projects that I have built
</h1>
</div>
</div>
</section>
<section class="section">
<div class="container is-fluid">
<div class="columns is-multiline">
<div class="column is-one-third" v-for="project in projects">
<post-card v-bind="project"></post-card>
</div>
</div>
</div>
</section>
</div>
</template>
这里要注意的是,v-for="project in projects"
我们post-card
为每个项目创建一个实例,并使用传递项目详细信息v-bind
。
模板的脚本部分如下所示:
<script>
import ProjectsService from '@/services/ProjectsService'
import PostCard from '@/components/PostCard'
export default {
name: "projects",
components: {
PostCard
},
data() {
return{
airtableResponse: []
}
},
mounted: function () {
let self = this
async function getProjects() {
try{
const response = await ProjectsService.getProjects()
console.log(response)
self.airtableResponse = response.data.records
}catch(err){
console.log(err)
}
}
getProjects()
},
computed: {
projects(){
let self = this
let projectList = []
for (var i = 0; i < self.airtableResponse.length; i++) {
if (self.airtableResponse[i].fields.Published){
let project = {
title: self.airtableResponse[i].fields.Title,
date: self.airtableResponse[i].fields["Date Published"],
snippet: self.airtableResponse[i].fields.Excerpt,
image: self.airtableResponse[i].fields.Image[0].url,
slug: self.airtableResponse[i].fields.slug
}
projectList.push(project)
}
}
return projectList
}
}
};
</script>
从顶部开始,发生的事情如下:
- 导入我们之前创建的 ProjectsService 和 PostCard
- 设置一个变量来保存来自 Airtable 的响应
- 当组件挂载的时候,调用我们在服务中设置的端点。
- 将我们需要的响应部分放入 airtableResponse 变量中。
- 使用名为“Projects”的数组创建计算属性,其中 Airtable 响应中的每个已发布项目都有一个对象,每张卡片都需要一个变量。
如果一切顺利,您应该能够/projects
在网格中加载并查看在 Airtable 中创建的每个项目
克里特岛项目视图
还记得我们路由器设置中的这段代码吗?
{
path: "/project/:slug",
name: "project",
component: Project
}
它将使我们能够访问我们的 Project 组件中的 slug,并将其传递到我们的 Projects Service 中,以便我们可以使用该 slug Airtable 检索该项目的所有信息。
让我们在中添加一个调用ProjectsService.js
:
getProject(slug) {
return Axios.get("?filterByFormula={Slug}='" + slug + "'")
}
我们在这里使用 Airtable 的 API 功能来搜索包含 slug 的帖子并返回它。
现在让我们创建我们的项目视图模板:
<template>
<div>
<section class="hero is-medium is-primary is-bold">
<div class="hero-body">
<div class="container">
<h1 class="title is-2">
{{project.title}}
</h1>
<h2 class="subtitle is-4">
{{project.snippet}}
</h2>
</div>
</div>
</section>
<section class="section">
<div class="container is-fluid">
<div class="columns">
<div class="column is-two-thirds">
<vue-simple-markdown :source="project.body"></vue-simple-markdown>
</div>
<div class="column is-one-third">
<div class="columns is-multiline">
<div class="column is-full" v-for="image in project.images">
<img :src="image.url"/>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
此模板使用了我们之前安装的 VueSimpleMarkdown 插件。这意味着您可以在 Airtable 的 body 字段中使用 markdown 来设置项目样式。我们将 body 显示在左侧的一列中,并将该项目的所有图片显示在右侧。
最后是项目组件的脚本部分:
<script>
import ProjectsService from '@/services/ProjectsService'
import PostCard from '@/components/PostCard'
export default {
name: "project",
components: {
PostCard
},
data() {
return{
airtableResponse: []
}
},
mounted: function () {
let self = this
console.log("here 1")
async function getProject() {
try{
const response = await ProjectsService.getProject(self.$route.params.slug)
console.log(response)
self.airtableResponse = response.data.records
}catch(err){
console.log(err)
}
}
getProject()
},
computed: {
project(){
let self = this
if (self.airtableResponse[0]){
let thisProject = {
title: self.airtableResponse[0].fields.Title,
snippet: self.airtableResponse[0].fields.Excerpt,
images: self.airtableResponse[0].fields.Image,
body: self.airtableResponse[0].fields.Body
}
return thisProject
}
}
}
};
</script>
与“项目”视图类似,但这次我们将 slug 传递给调用getProject
。如果 slug 是唯一的,我们应该只会收到一个响应。
前往 /projects/[your-slug] 查看您的项目!
结论
呼!好多内容!现在我们完成了,一个用 Vue 构建、用 Bulma 设置样式的简单 CMS 站点,可以实时显示数据。太酷了!
我将尝试各种样式,添加一些新功能,并清理一些东西,所以请关注hellomark.dev看看接下来会发生什么!
请告诉我您对本教程的看法以及您有的任何问题!
文章来源:https://dev.to/markjohnson303/building-a-portfolio-site-with-vue-bulma-and-airtable-5a58