Thứ hai, 01/01/2018 | 00:00 GMT+7

Cập nhật Tiêu đề và Siêu dữ liệu của Trang với bộ định tuyến Vue.js & vue


vue-router là một giải pháp định tuyến tuyệt vời cho Vue.js, nhưng có một điều mà nó không xử lý được có thể khiến các nhà phát triển (đặc biệt là những người có kinh nghiệm với SEO) phát điên. Đó là quá trình cập nhật tiêu đề trang và metadata về sự thay đổi tuyến đường. Bây giờ nó có ý nghĩa rằng vue-router không gây rối với điều này. Vue cố gắng tránh xa các yếu tố trên headbody càng nhiều càng tốt, vì chúng có thể khá dễ bay hơi. Nhưng thường thì bạn cần tiêu đề của trình duyệt thay đổi khi trang thay đổi, phải không? Và bạn sẽ không muốn mọi kết quả tìm kiếm hoặc liên kết đến trang web có nội dung “Trang chủ” cho tất cả các tuyến đường. Vì vậy, ta hãy xem cách tự thêm tính năng này.

Bắt đầu

Bắt đầu một dự án Vue đơn giản với vue-cli và mẫu webpack-simple .

Sau đó, cài đặt vue-router .

# Yarn
$ yarn add vue-router
# NPM
$ npm install vue-router --save

Cấu hình tuyến đường mà ta sẽ hướng tới sẽ như sau:

/ - Home Page
/about - About Page (Really just the home page again...)
 | /nested - A secret nested page

Cài đặt ban đầu

Hãy tiếp tục và chuẩn bị sẵn sàng cấu hình và file main.js ban đầu. Ta sẽ tạo và sửa đổi các file khác sau. Phiên bản này sẽ không xử lý việc đặt tiêu đề.

main.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import Nested from './Nested.vue';

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    component: App,
    meta: {
      title: 'Home Page - Example App',
      metaTags: [
        {
          name: 'description',
          content: 'The home page of our example app.'
        },
        {
          property: 'og:description',
          content: 'The home page of our example app.'
        }
      ]
    }
  },
  {
    path: '/about',
    // I'm kind of cheating by reusing the main app component here.
    component: App,
    meta: {
      title: 'About Page - Example App',
      metaTags: [
        {
          name: 'description',
          content: 'The about page of our example app.'
        },
        {
          property: 'og:description',
          content: 'The about page of our example app.'
        }
      ]
    },

    children: [
      {
        path: 'nested',
        component: Nested,
        meta: {
          title: 'Nested - About Page - Example App'
        }
      }
    ]
  }
];

const router = new VueRouter({
  routes,
  mode: 'history'
});

new Vue({
  router,
  template: ''
})
.$mount('#app');

Bạn sẽ thấy rằng mỗi tuyến có một tùy chọn meta bổ sung, chứa title , cuối cùng sẽ là tiêu đề tuyến và metaTags , một đối tượng mà sau này ta sẽ chuyển thành các thẻ meta của trang. ( Ta vẫn chưa hoàn thành.)

Các mẫu

Trong file App.vue được cung cấp, hãy thêm một vài liên kết bộ định tuyến và chế độ xem bộ định tuyến cho trang lồng nhau.

App.vue
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <h1>{{msg}}</h1>
    <h2>Essential Links</h2>
    <ul>
      <li><router-link to="/">Home</router-link></li>
      <li><router-link to="/about">About</router-link></li>
      <li><router-link to="/about/nested">Nested Route</router-link></li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
      <li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
      <li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
      <li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
    </ul>
    <router-view></router-view>
  </div>
</template>
...

Bây giờ, hãy tạo một file mới có tên Nested.vue bên cạnh App.vue .

Nested.vue
<template>
  <p>You've found a hidden alligator nest!</p>
</template>

Thay đổi thẻ tiêu đề & thẻ meta

Được rồi, tuyệt vời, nếu bạn chạy npm run dev bây giờ, bạn sẽ thấy ứng dụng hiển thị đúng cách và phải có thể nhấp vào liên kết để chuyển các tuyến đường. Hoan hô. Nhưng chờ đã, tiêu đề và thẻ meta vẫn chưa thay đổi.

Đối với điều đó, ta cần một bộ bảo vệ chuyển tùy chỉnh cho bộ định tuyến trong main.js Hãy để tôi ném một số mã vào bạn.

main.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import Nested from './Nested.vue';

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    component: App,
    meta: {
      title: 'Home Page - Example App',
      metaTags: [
        {
          name: 'description',
          content: 'The home page of our example app.'
        },
        {
          property: 'og:description',
          content: 'The home page of our example app.'
        }
      ]
    }
  },
  {
    path: '/about',
    // I'm kind of cheating by reusing the main app component here.
    component: App,
    meta: {
      title: 'About Page - Example App',
      metaTags: [
        {
          name: 'description',
          content: 'The about page of our example app.'
        },
        {
          property: 'og:description',
          content: 'The about page of our example app.'
        }
      ]
    },

    children: [
      {
        path: 'nested',
        component: Nested,
        meta: {
          title: 'Nested - About Page - Example App'
        }
      }
    ]
  }
];

// This callback runs before every route change, including on page load.
router.beforeEach((to, from, next) => {
  // This goes through the matched routes from last to first, finding the closest route with a title.
  // eg. if we have /some/deep/nested/route and /some, /deep, and /nested have titles, nested's will be chosen.
  const nearestWithTitle = to.matched.slice().reverse().find(r => r.meta && r.meta.title);

  // Find the nearest route element with meta tags.
  const nearestWithMeta = to.matched.slice().reverse().find(r => r.meta && r.meta.metaTags);
  const previousNearestWithMeta = from.matched.slice().reverse().find(r => r.meta && r.meta.metaTags);

  // If a route with a title was found, set the document (page) title to that value.
  if(nearestWithTitle) document.title = nearestWithTitle.meta.title;

  // Remove any stale meta tags from the document using the key attribute we set below.
  Array.from(document.querySelectorAll('[data-vue-router-controlled]')).map(el => el.parentNode.removeChild(el));

  // Skip rendering meta tags if there are none.
  if(!nearestWithMeta) return next();

  // Turn the meta tag definitions into actual elements in the head.
  nearestWithMeta.meta.metaTags.map(tagDef => {
    const tag = document.createElement('meta');

    Object.keys(tagDef).forEach(key => {
      tag.setAttribute(key, tagDef[key]);
    });

    // We use this to track which meta tags we create, so we don't interfere with other ones.
    tag.setAttribute('data-vue-router-controlled', '');

    return tag;
  })
  // Add the meta tags to the document head.
  .forEach(tag => document.head.appendChild(tag));

  next();
});

const router = new VueRouter({
  routes,
  mode: 'history'
});

new Vue({
  router,
  template: ''
})
.$mount('#app');

Đó phải là thủ thuật. Bây giờ khi các tuyến đường của bạn thay đổi, tiêu đề trang sẽ được cập nhật với tiêu đề của tuyến đường phù hợp nhất và các thẻ meta cũng sẽ cập nhật. Nếu bạn sử dụng kết xuất trước , thì những thay đổi này sẽ được đưa vào các file HTML được kết xuất trước của bạn và sẽ hoạt động tốt cho SEO. Đối với SSR, nó có thể khó hơn một chút. Ta sẽ đề cập đến vấn đề đó sau.

Cũng cần lưu ý các tiêu đề động, thường xuyên cập nhật không phải là câu hỏi với phương pháp này. Có thể bạn sẽ phải cập nhật document.title theo cách thủ công cho các trường hợp sử dụng như vậy.


Tags:

Các tin liên quan