diff --git a/example/main.tsx b/example/main.tsx index 9b68dd8..47b89a0 100644 --- a/example/main.tsx +++ b/example/main.tsx @@ -7,11 +7,30 @@ import { } from 'vue-router' import { createHead, useHead } from '../src' -const Home = defineComponent({ +const Counter = defineComponent({ setup() { const count = ref(0) useHead({ title: computed(() => `count: ${count.value}`), + }) + return () => ( + + ) + }, +}) + +const Home = defineComponent({ + setup() { + const title = ref('Home') + useHead({ + title, base: { href: '/' }, style: [{ children: `body {background: red}` }], htmlAttrs: { @@ -44,12 +63,12 @@ const Home = defineComponent({ About
+ ) }, diff --git a/src/index.ts b/src/index.ts index 1c92b04..323d41a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -50,6 +50,8 @@ export type Head = { removeHeadTags: (tags: HeadTag[]) => void + updateHeadTags: (oldTags: HeadTag[], newTags: HeadTag[]) => void + updateDOM: (document?: Document) => void } @@ -211,7 +213,7 @@ const insertTags = (tags: HeadTag[], document = window.document) => { } export const createHead = () => { - const headTags: HeadTag[] = [] + let allHeadTags: HeadTag[][] = [] const head: Head = { install(app) { @@ -219,47 +221,64 @@ export const createHead = () => { app.provide(PROVIDE_KEY, head) }, - headTags, - - addHeadTags(tags) { - tags.forEach((tag) => { - if (tag.tag === 'meta' || tag.tag === 'base') { - // Remove tags with the same key - const key = getTagKey(tag.props) - if (key) { - let index = -1 - - for (let i = 0; i < headTags.length; i++) { - const prev = headTags[i] - const prevValue = prev.props[key.name] - const nextValue = tag.props[key.name] - if (prev.tag === tag.tag && prevValue === nextValue) { - index = i - break + /** + * Get deduped tags + */ + get headTags() { + const deduped: HeadTag[] = [] + + allHeadTags.forEach((tags) => { + tags.forEach((tag) => { + if (tag.tag === 'meta' || tag.tag === 'base') { + // Remove tags with the same key + const key = getTagKey(tag.props) + if (key) { + let index = -1 + + for (let i = 0; i < deduped.length; i++) { + const prev = deduped[i] + const prevValue = prev.props[key.name] + const nextValue = tag.props[key.name] + if (prev.tag === tag.tag && prevValue === nextValue) { + index = i + break + } } - } - if (index !== -1) { - headTags.splice(index, 1) + if (index !== -1) { + deduped.splice(index, 1) + } } } - } - headTags.push(tag) + deduped.push(tag) + }) }) + + return deduped }, - removeHeadTags(tags) { - tags.forEach((tag) => { - const index = headTags.indexOf(tag) - if (index !== -1) { - headTags.splice(index, 1) + addHeadTags(tags) { + allHeadTags.push(tags) + }, + + updateHeadTags(oldTags, newTags) { + allHeadTags = allHeadTags.map((v) => { + if (v === oldTags) { + return newTags } + return v + }) + }, + + removeHeadTags(tags) { + allHeadTags = allHeadTags.filter((v) => { + return tags !== v }) }, updateDOM(document) { - insertTags(headTags, document) + insertTags(head.headTags, document) }, } return head @@ -277,19 +296,24 @@ export const useHead = ( if (IS_BROWSER) { let tags: HeadTag[] | undefined + let oldTags: HeadTag[] | undefined watchEffect(() => { - if (tags) { - head.removeHeadTags(tags) - } tags = headObjToTags(headObj.value) - head.addHeadTags(tags) + + if (oldTags) { + head.updateHeadTags(oldTags, tags) + } else { + head.addHeadTags(tags) + } + + oldTags = tags head.updateDOM() }) onBeforeUnmount(() => { - if (tags) { - head.removeHeadTags(tags) + if (oldTags) { + head.removeHeadTags(oldTags) head.updateDOM() } }) diff --git a/tests/test.tsx b/tests/test.tsx index 14b5486..305e812 100644 --- a/tests/test.tsx +++ b/tests/test.tsx @@ -83,7 +83,10 @@ test('browser', async (t) => { `, ) - await page.click('button') + await page.click('button.counter') + t.is(await page.title(), 'count: 1') + + await page.click('button.change-home-title') t.is(await page.title(), 'count: 1') await page.click('a[href="/about"]')