head.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import { watchEffect } from 'vue';
  2. export function useUpdateHead(route, siteDataByRouteRef) {
  3. const metaTags = Array.from(document.querySelectorAll('meta'));
  4. let isFirstUpdate = true;
  5. const updateHeadTags = (newTags) => {
  6. if (process.env.NODE_ENV === 'production' && isFirstUpdate) {
  7. // in production, the initial meta tags are already pre-rendered so we
  8. // skip the first update.
  9. isFirstUpdate = false;
  10. return;
  11. }
  12. metaTags.forEach((el) => document.head.removeChild(el));
  13. metaTags.length = 0;
  14. if (newTags && newTags.length) {
  15. newTags.forEach((headConfig) => {
  16. const el = createHeadElement(headConfig);
  17. document.head.appendChild(el);
  18. metaTags.push(el);
  19. });
  20. }
  21. };
  22. watchEffect(() => {
  23. const pageData = route.data;
  24. const siteData = siteDataByRouteRef.value;
  25. const pageTitle = pageData && pageData.title;
  26. document.title = (pageTitle ? pageTitle + ` | ` : ``) + siteData.title;
  27. updateHeadTags([
  28. ['meta', { charset: 'utf-8' }],
  29. [
  30. 'meta',
  31. {
  32. name: 'viewport',
  33. content: 'width=device-width,initial-scale=1'
  34. }
  35. ],
  36. [
  37. 'meta',
  38. {
  39. name: 'description',
  40. content: siteData.description
  41. }
  42. ],
  43. ...siteData.head,
  44. ...((pageData && pageData.frontmatter.head) || [])
  45. ]);
  46. });
  47. }
  48. function createHeadElement([tag, attrs, innerHTML]) {
  49. const el = document.createElement(tag);
  50. for (const key in attrs) {
  51. el.setAttribute(key, attrs[key]);
  52. }
  53. if (innerHTML) {
  54. el.innerHTML = innerHTML;
  55. }
  56. return el;
  57. }