JS

Как создать сайт с безсерверной CMS на Vue.js

От автора: сегодня мы поговорим о создании с помощью Vue js CMS. Vue.js – это прогрессивный фреймворк для создания UI, набирающий популярность среди разработчиков. Но зачем нам еще один JS фреймворк? Vue написан на опыте Angular и React, многие считают, что он проще в реализации и понимании.

Введение

Vue.js мало весит и легко принимается. Он реактивный и состоит из компонентов, что позволяет создавать подключаемые компоненты, которые можно добавлять в любой проект. Что важнее для этого урока, Vue со своей отличительной и постепенной адаптируемостью можно использовать, не подвергая риску существующий код.

Vue превосходно работает с безсерверными архитектурами приложений. Множество разработчиков сейчас предпочитают безсерверную архитектуру, так как она позволяет эффективно создавать и точно настраивать продукты, не обременяя себя (обслуживание серверов, сбои и узкие места) традиционной серверной архитектурой. Sarah Drasner недавно написала целую серию о том, как создать безсерверную корзину на Vue – хороший пример на практике.

В этом уроке вы узнаете, как создавать маркетинговые сайты в виде безсерверного приложения Vue.js с помощью ButterCMS. ButterCMS – это обезглавленная CMS и блог-платформа, позволяющая создавать приложения под управлением CMS, используя при этом любой язык программирования, в том числе и Vue. Есть и другие варианты для работы с обезглавленными CMS, но так как я раньше писал для ButterCMS и хорошо ее знаю, поэтому ее мы и будем использовать в примерах.

В этом уроке вы узнаете, как добавить производительные API контента в приложение Vue.js. По этим API легко перемещаться даже членам команды с нетехническим складом ума, что позволяет получать удовольствие от гибкого управления контентом и не развертывать/поддерживать собственную CMS.

В частности, мы разберем примеры кода для трех типов контента, встречающегося на маркетинговых сайтах: отзывы покупателей, часто задаваемые вопросы и посты в блоге.

Обратите внимание на то, что скриншоты в статье будут отличаться от ваших, на них будем минимум CSS для демонстрации. В вашем настоящем дизайне будут использоваться глобальные стили приложения, которые будут придавать страницам единообразие.

Начало работы

В качестве CMS мы будем использовать ButterCMS. Так давайте же установим ее:

npm install buttercms--save

После установки можно перейти к примерам.

Пример 1: отзывы покупателей

Давайте сделаем так, чтобы любой человек без технического склада ума в вашей команде мог добавить отзывы покупателей на сайт. Для этого мы создадим страницу, на которой будут храниться все опубликованные отзывы, рекламирующие продукт или услугу, которую мы продаем. При нажатии будет открываться страница отзыва.

Шаг 1: настройка типа страницы отзыва покупателя

В панели управления ButterCMS можно создать «тип страниц» с заголовком «Customer Case Study» и определить поля контента. После этого можно создавать первую страницу. Укажите название и URL страницы с помощью панели управления ButterCMS и заполните поля контента тем, что мы только что определили.

После всего 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>rn<p><img src="https://webformyself.com/https://cdn.buttercms.com/NiA3IIP3Ssurz5eNJ15a" alt="Создание безсерверной CMS под управлением Vue.js" caption="false" width="249" height="249" /></p>",
      "customer_logo":"https://cdn.buttercms.com/c8oSTGcwQDC5I58km5WV",
    }
  }
}

Шаг 2: интеграция с приложением

Откройте редактор кода и создайте файл buttercms.js в папке /src. Если у вас еще нет проекта, создайте его, введя следующие команды:

vue init webpack buttercms-project
cd buttercms-project
npmi
npmi-Sbuttercms
npm run dev

Затем в файле src/buttercms.js:

import Butter from'buttercms';
constbutter=Butter('your_api_token');

Обновите роуты в приложении. Сделать это можно в router/index.js:

import Vue from'vue';
import Router from'vue-router';
import CustomersHome from'@/components/CustomersHome';
import CustomerPage from'@/components/CustomerPage';
Vue.use(Router)
exportdefaultnewRouter({
  mode:'history',
  routes:[
    {
      path:'/customers/',
      name:'customers-home',
      component:CustomersHome
    },
    {
      path:'/customers/:slug',
      name:'customer-page',
      component:CustomerPage
    }
  ]
})

Отлично, у вас есть контента в файле данных. Теперь вам нужна страница, которая будет использовать этот контент. Необходимо определить метод getpages(), который будет получать все страницы отзывов, чтобы вы могли отрендерить их все на одной лендинг пейдж (чтобы у них у всех был индекс). Это будет домашняя страница для всех опубликованных отзывов.

В файле components/CustomersHome.vue добавьте:

<script>
  // import ButterCMS from
  import{butter}from'@/buttercms'
  exportdefault{
    name:'customers-home',
    data(){
      return{
        page_title:'Customers',
        // Create array to hold the pages from ButterCMS API
        pages:[]
      }
    },
    methods:{
      // Get List of Customer Pages
      getPages(){
        butter.page.list('customer_case_study')
          .then((res)=>{
            // console.log(res.data.data) // Check the results in the console
            this.pages=res.data.data
          })
      }
    },
    created(){
      // Fire on page creation
      this.getPages()
    }
  }
</script>

… чтобы отобразить результаты по одному:

<template>
  <div id="customers-home">
    <h1>{{page_title}}</h1>
    <div v-for="(page,index) in pages":key="page.slug + '_' + index">
      <router-link:to="'/customers/' + page.slug">
        <div>
          <img:src="page.fields.customer_logo"alt="">
          <h2>{{page.fields.headline}}</h2>
        </div>
      </router-link>
    </div>
  </div>
</template>

Ниже показан пример того, что должно получиться после публикации одного отзыва:

Теперь необходимо создать страницу, на которую мы будем переходить по клику на отзыв с домашней страницы. Для этого определите метод getPage() в файле components/CustomerPage.vue, чтобы получить конкретную страницу покупателя по ее уникальному идентификатору:

<script>
  import{butter}from'@/buttercms'
  exportdefault{
    name:'customer-page',
    data(){
      return{
        slug:this.$route.params.slug,
        page:{
          slug:'',
          fields:{}
        }
      }
    },
    methods:{
      getPage(){
        butter.page.retrieve('customer_case_study',this.slug)
          .then((res)=>{
            console.log(res.data.data)
            this.page=res.data.data
          }).catch((res)=>{
            console.log(res)
          })
      }
    },
    created(){
      this.getPage()
    }
  }
</script>

Как и с домашней страницей и отзывами, необходимо показать контент, задав шаблон и вызвав нужные поля контента:

<template>
  <div id="customer-page">
    <figure>
      <img:src="page.fields.customer_logo">
    </figure>
    <h1>{{page.fields.headline}}</h1>
    <h3>Testimonials</h3>
    <div v-html="page.fields.testimonial"></div>
    <div v-html="page.fields.body"></div>
  </div>
</template>

Отлично! Теперь вы можете переходить прямо на страницу со всеми опубликованными отзывами, а по клику на любой отзыв вы переходите на детальную страницу.


Пример 2: часто задаваемые вопросы

Давайте посмотрим, как создать страницу часто задаваемых вопросов (FAQ) для приложения. Для этого будем использовать ButterCMS «Content Fields». Content fields – это просто глобальные части контента, которыми может управлять команда. Этот контент может распространяться на несколько страниц, а у каждого content field (поля контента) есть свой уникальный ID для запроса (это вы увидите ниже).

Шаг 1: настройка полей контента

Сперва, необходимо настроить несколько пользовательских полей контента. С помощью панели управления можно настроить рабочую область для организации полей контента. Рабочие области позволяют редакторам контента работать с ним, не затрагивая разработку или API.

В рабочей области кликните на кнопку, чтобы создать новое поле контента. Выберите тип Object, в качестве названия поля укажите FAQ Headline. Поле получит свой API идентификатор — faq_headline.

После сохранения добавьте еще одно поле, но в этот раз выберите тип Collection и название поля FAQ Items. Это поле получит API id — faq_items. На следующем экране создайте 2 свойства для элементов в коллекции и вернитесь в рабочую область, чтобы обновить заголовки и добавить посты в FAQ.

Шаг 2: интеграция с приложением

После создания динамического контента на основе полей контента необходимо его отобразить в приложении. Для этого необходимо получить поля с помощью запроса к API и передать их в представление. Сперва, настройте роут на страницу FAQ:

Добавим роуты FAQ в файл router/index.js:

import Vue from'vue';
import Router from'vue-router';
import FAQ from'@/components/FAQ';
Vue.use(Router);
exportdefaultnewRouter({
  mode:'history',
  routes:[
    {
      path:'/faq',
      name:'faq',
      component:FAQ
    }
  ]
})

Создайте components/FAQ.vue с запросом на получение FAQ контента из API:

<script>
  import{butter}from'@/buttercms'
  exportdefault{
    name:'faq',
    data(){
      return{
        page_title:'FAQ',
        faq_items:[]
      }
    },
    methods:{
      getFaqs(){
        butter.content.retrieve(['faq_headline','faq_items'])
          .then((res)=>{
            console.log(res.data.data)
            this.page_title=res.data.data.faq_headline
            this.faq_items=res.data.data.faq_items
          })
      }
    },
    created(){
      this.getFaqs()
    }
  }
</script>

Обратите внимание, что мы заранее указали page_title как FAQ и обновили его с помощью API запроса к полям контента FAQ.

Создайте <template>:

<template>
  <div id="faq">
    <h1>{{page_title}}</h1>
    <div v-for="(faq, index) in faq_items":key="index">
      <p>{{faq.question}}</p>
      <p>{{faq.answer}}</p>
    </div>
  </div>
</template>

Результат должен быть примерно такой:

Теперь любой человек из вашей команды может обновить значения через панель управления ButterCMS, и соответствующий контент в приложении обновится автоматически.


Пример 3: посты в блоге

Разберем механизм блога для приложения.

Шаг 1: отображение постов

Начну с создания роута блога с помощью vue-router. Для отображения постов необходимо создать простой роут /blog и получать посты блога, а также роут /blog/:slug для обработки отдельных постов.

Файл router/index.js:

import Vue from 'vue';
import Router from 'vue-router';
import BlogHome from '@/components/BlogHome';
import BlogPost from'@/components/BlogPost';
Vue.use(Router)
exportdefaultnewRouter({
  mode:'history',
  routes:[
    {
      path:'/blog/',
      name:'blog-home',
      component:BlogHome
    },
    {
      path:'/blog/:slug',
      name:'blog-post',
      component:BlogPost
    }
  ]
})

Шаг 2: создание домашней страницы блога

Чтобы создать домашнюю страницу блога, на которой будут отображаться последние опубликованные посты, необходимо создать Vue компонент для домашней страницы блога в файле components/BlogHome.vue:

<script>
  import{butter}from'@/buttercms'
  exportdefault{
    name:'blog-home',
    data(){
      return{
        page_title:'Blog',
        posts:[]
      }
    },
    methods:{
      getPosts(){
        butter.post.list({
          page:1,
          page_size:10
        }).then((res)=>{
          // console.log(res.data)
          this.posts=res.data.data
        })
      }
    },
    created(){
      this.getPosts()
    }
  }
</script>

Если вы разобрали предыдущие примеры, то могли заметить здесь шаблон и понять, что для отображения контента необходимо определить шаблон и вызвать поля в том же файле компонента:

<template>
  <div id="blog-home">
      <h1>{{page_title}}</h1>
      <div v-for="(post,index) in posts":key="post.slug + '_' + index">
        <router-link:to="'/blog/' + post.slug">
          <article class="media">
            <figure>
              <img v-if="post.featured_image":src="post.featured_image"alt="">
              <img v-elsesrc="http://via.placeholder.com/250x250"alt="">
            </figure>
            <h2>{{post.title}}</h2>
            <p>{{post.summary}}</p>
          </article>
        </router-link>
      </div>
  </div>
</template>

Если ваши поля совпадают с примером, то домашняя страница блога должна быть примерно такой:

Шаг 3: создание поста в блоге

Далее создайте файл components/BlogPost.vue – это будет представление для одного поста:

<script>
  import{butter}from'@/buttercms'
  exportdefault{
    name:'blog-post',
    data(){
      return{
        post:{}
      }
    },
    methods:{
      getPost(){
        butter.post.retrieve(this.$route.params.slug)
          .then((res)=>{
            // console.log(res.data)
            this.post=res.data
          }).catch((res)=>{
            console.log(res)
          })
      }
    },
    created(){
      this.getPost()
    }
  }
</script>

Вы могли догадаться, но здесь необходимо определить шаблон и послать запрос на поля контента поста в блоге:

<template>
  <div id="blog-post">
    <h1>{{post.data.title}}</h1>
    <h4>{{post.data.author.first_name}}{{post.data.author.last_name}}</h4>
    <div v-html="post.data.body"></div>
    <router-link v-if="post.meta.previous_post":to="/blog/ + post.meta.previous_post.slug"class="button">
      {{post.meta.previous_post.title}}
    </router-link>
    <router-link v-if="post.meta.next_post":to="/blog/ + post.meta.next_post.slug"class="button">
      {{post.meta.next_post.title}}
    </router-link>
  </div>
</template>

Если ваши поля совпадают с примером, то получиться должно примерно следующее:

Шаг 4: обработка роутов постов блога

На данном этапе ваше приложение получает все посты блога, что позволяет перейти к отдельным постам. Но вы заметили, что кнопки назад/вперед в браузере не работают? Почему? Если роут используется с params, то будет задействован тот же объект компонента, когда пользователь перейдет с /blog/foo на /blog/bar.

Такой способ эффективнее уничтожения старого объекта и создания нового, так как оба роута рендерят один компонент. Но это так же значит, что не вызываются хуки жизненного цикла компонента.

Это можно починить. Необходимо следить за объектом $route и вызывать getPost(), когда роут изменяется. Для этого обновите раздел script в файле components/BlogPost.vue:

<script>
  import{butter}from'@/buttercms';
  exportdefault{
    name:'blog-post',
    data(){
      return{
        post:{}
      }
    },
    methods:{
      getPost(){
        butter.post.retrieve(this.$route.params.slug)
          .then((res)=>{
            // console.log(res.data)
            this.post=res.data
          }).catch((res)=>{
            console.log(res)
          })
      }
    },
    watch:{
      $route(to,from){
        this.getPost()
      }
    },
    created(){
      this.getPost()
    }
  }
</script>

Сейчас в вашем приложении есть рабочий блог, который легко можно обновлять через панель управления CMS.

Также с помощью API можно применять фильтры и использовать избранный контент в блоге на категориях, тегах и авторах. С точки зрения управления различными аспектами блога (RSS, Atom feeds, карта сайта и стилизация контента через CSS) можно много чего сделать через API.

Заключение

Поздравляю! Вы создали безсерверное приложение Vue.js с производительным API контента. Теперь вы имеете реальные примеры использования контента, который можно встретить на любом маркетинговом сайте. Ваши разработчики могут вернуться к программированию, а не технари получили легкий способ управления контентом без необходимости лезть в код. Что еще лучше, приложение работает с динамическим контентом, который может адаптироваться, переназначаться и масштабироваться под будущие нужды.

Автор: Jake Lumetta

Источник: https://css-tricks.com/

Редакция: Команда webformyself.

Поделится
Admin

Recent Posts

Разработка игр на Unity

В Unity используется производительный язык программирования C#. Благодаря C# и Mono – кроссплатформенной реализации .NET,…

1 год ago