mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-25 11:20:33 +03:00
feat: improve useApi
This commit is contained in:
@@ -10,17 +10,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const mapping = inject('__vueMetaConfig')
|
|
||||||
|
|
||||||
return {
|
|
||||||
mapping
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const targets = {}
|
const targets = {}
|
||||||
|
|
||||||
for (const key in this.metainfo) {
|
for (const key in this.metainfo) {
|
||||||
const config = this.mapping[key] || {}
|
const config = this.$metaInfo.config[key] || {}
|
||||||
|
|
||||||
const vnodes = renderMeta(this, key, this.metainfo[key], config)
|
const vnodes = renderMeta(this, key, this.metainfo[key], config)
|
||||||
let target = (key !== 'base' && this.metainfo[key].target) || config.target || 'head'
|
let target = (key !== 'base' && this.metainfo[key].target) || config.target || 'head'
|
||||||
|
|||||||
+82
-53
@@ -1,9 +1,12 @@
|
|||||||
import { markRaw, reactive, onMounted, customRef, getCurrentInstance } from 'vue'
|
import { markRaw, reactive, onUnmounted, getCurrentInstance } from 'vue'
|
||||||
import { def, hasOwn, isObject, isArray, isPlainObject } from '@vue/shared'
|
import { hasOwn, isObject, isArray, isPlainObject } from '@vue/shared'
|
||||||
import { defaultMapping } from './config'
|
import { defaultMapping } from './config'
|
||||||
|
|
||||||
let appId = 0
|
let appId = 0
|
||||||
|
|
||||||
|
const shadow = markRaw({})
|
||||||
|
const metainfo = reactive({})
|
||||||
|
|
||||||
export function createMeta ({ resolver, config }) {
|
export function createMeta ({ resolver, config }) {
|
||||||
const id = Symbol(`vueMeta[${appId++}]`)
|
const id = Symbol(`vueMeta[${appId++}]`)
|
||||||
|
|
||||||
@@ -12,116 +15,142 @@ export function createMeta ({ resolver, config }) {
|
|||||||
const $metaInfo = {
|
const $metaInfo = {
|
||||||
id,
|
id,
|
||||||
resolver,
|
resolver,
|
||||||
shadow: markRaw({}),
|
config: {
|
||||||
metainfo: reactive({})
|
...defaultMapping,
|
||||||
|
...config
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.config.globalProperties.$metaInfo = $metaInfo
|
app.config.globalProperties.$metaInfo = $metaInfo
|
||||||
app.provide('metainfo', $metaInfo.metainfo)
|
app.provide('metainfo', metainfo)
|
||||||
app.provide('__vueMetaConfig', {
|
|
||||||
id,
|
|
||||||
...defaultMapping,
|
|
||||||
...config
|
|
||||||
})
|
|
||||||
|
|
||||||
app.config.globalProperties.$meta = this
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMeta (obj) {
|
export function useMeta (obj, context) {
|
||||||
const vm = getCurrentInstance()
|
// set empty object to remove everything
|
||||||
|
const unmount = () => setMetainfoByObject(context, {}, shadow, metainfo)
|
||||||
|
|
||||||
const { shadow, metainfo } = vm.ctx.$metaInfo
|
if (!context) {
|
||||||
addMetainfoRecursive(obj, vm, shadow, metainfo)
|
context = getCurrentInstance()
|
||||||
|
|
||||||
return createProxy(obj, createHandler(vm))
|
onUnmounted(unmount)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
context = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
setMetainfoByObject(context, obj, shadow, metainfo)
|
||||||
|
|
||||||
|
const meta = createProxy(obj, createHandler(context))
|
||||||
|
|
||||||
|
return {
|
||||||
|
meta,
|
||||||
|
unmount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createProxy (obj, handler) {
|
function createProxy (obj, handler) {
|
||||||
return new Proxy(obj, handler)
|
return markRaw(new Proxy(obj, handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
function createHandler (vm, keyPath = []) {
|
function createHandler (context, keyPath = []) {
|
||||||
return {
|
return {
|
||||||
get (target, prop) {
|
get (target, prop) {
|
||||||
const value = target[prop]
|
const value = target[prop]
|
||||||
|
|
||||||
if (isObject(value)) {
|
if (!isObject(value)) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
if (!value.__vm_proxy) {
|
if (!value.__vm_proxy) {
|
||||||
const newKeyPath = [...keyPath, prop]
|
const newKeyPath = [...keyPath, prop]
|
||||||
|
|
||||||
const handler = createHandler(vm, newKeyPath)
|
const handler = createHandler(context, newKeyPath)
|
||||||
value.__vm_proxy = createProxy(value, handler)
|
value.__vm_proxy = createProxy(value, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
return value.__vm_proxy
|
return value.__vm_proxy
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
},
|
},
|
||||||
set (target, prop, value) {
|
set (target, prop, value) {
|
||||||
updateMetainfo(keyPath, vm, prop, value)
|
updateMetainfo(keyPath, context, prop, value)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMetainfoRecursive (obj, vm, shadowParent, liveParent) {
|
function setMetainfo (context, key, value, shadowParent, liveParent, keyTree = []) {
|
||||||
for (const key in obj) {
|
if (isPlainObject(value)) {
|
||||||
if (isPlainObject(obj[key])) {
|
|
||||||
if (!shadowParent[key]) {
|
if (!shadowParent[key]) {
|
||||||
shadowParent[key] = {}
|
shadowParent[key] = {}
|
||||||
liveParent[key] = {}
|
liveParent[key] = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
addMetainfoRecursive(obj[key], vm, shadowParent[key], liveParent[key])
|
return setMetainfoByObject(context, value, shadowParent[key], liveParent[key], keyTree)
|
||||||
|
}
|
||||||
|
|
||||||
|
let idx = -1
|
||||||
|
if (!hasOwn(shadowParent, key)) {
|
||||||
|
shadowParent[key] = []
|
||||||
|
} else {
|
||||||
|
idx = shadowParent[key].findIndex(({ context: $context }) => $context === context)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx > -1 && value === undefined) {
|
||||||
|
shadowParent[key].splice(idx, 1)
|
||||||
|
} else if (idx > -1) {
|
||||||
|
shadowParent[key][idx].value = value
|
||||||
|
} else if (value) {
|
||||||
|
shadowParent[key].push({ context, value })
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveActiveMetainfo(context, key, keyTree, shadowParent, liveParent)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMetainfoByObject (context, obj, shadowParent, liveParent, keyTree = []) {
|
||||||
|
for (const key in shadowParent) {
|
||||||
|
if (hasOwn(obj, key)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shadowParent[key]) {
|
if (isPlainObject(shadowParent[key])) {
|
||||||
shadowParent[key] = []
|
setMetainfoByObject(context, {}, shadowParent[key], liveParent[key], [...keyTree, key])
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowParent[key].push({ vm, value: obj[key] })
|
setMetainfo(context, key, undefined, shadowParent, liveParent, [...keyTree, key])
|
||||||
|
}
|
||||||
|
|
||||||
setLive(vm, key, shadowParent, liveParent)
|
for (const key in obj) {
|
||||||
|
setMetainfo(context, key, obj[key], shadowParent, liveParent, [...keyTree, key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMetainfo (keyPath, vm, key, value) {
|
function updateMetainfo (keyPath, context, key, value) {
|
||||||
let { shadow: shadowParent, metainfo: liveParent } = vm.ctx.$metaInfo
|
let shadowParent = shadow
|
||||||
|
let liveParent = metainfo
|
||||||
|
|
||||||
for (const _key of keyPath) {
|
for (const _key of keyPath) {
|
||||||
shadowParent = shadowParent[_key]
|
shadowParent = shadowParent[_key]
|
||||||
liveParent = liveParent[_key]
|
liveParent = liveParent[_key]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPlainObject(value)) {
|
setMetainfo(context, key, value, shadowParent, liveParent)
|
||||||
if (!shadowParent[key]) {
|
|
||||||
shadowParent[key] = {}
|
|
||||||
liveParent[key] = {}
|
|
||||||
}
|
|
||||||
// TODO: fix this shit
|
|
||||||
addMetainfoRecursive(value, vm, shadowParent[key], liveParent[key])
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const idx = shadowParent[key].findIndex(({ vm: _vm }) => _vm === vm)
|
function resolveActiveMetainfo (context, key, keyTree, shadowParent, liveParent) {
|
||||||
shadowParent[key][idx].value = value
|
|
||||||
|
|
||||||
setLive(vm, key, shadowParent, liveParent)
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLive (vm, key, shadowParent, liveParent) {
|
|
||||||
let value
|
let value
|
||||||
|
|
||||||
if (shadowParent[key].length > 1) {
|
if (shadowParent[key].length > 1) {
|
||||||
value = vm.ctx.$metaInfo.resolver(shadowParent[key])
|
value = context.ctx.$metaInfo.resolver(key, shadowParent[key], liveParent[key])
|
||||||
} else {
|
} else if (shadowParent[key].length) {
|
||||||
value = shadowParent[key][0].value
|
value = shadowParent[key][0].value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasOwn(liveParent, key) || liveParent[key] !== value) {
|
if (value === undefined) {
|
||||||
|
delete liveParent[key]
|
||||||
|
} else if (!hasOwn(liveParent, key) || liveParent[key] !== value) {
|
||||||
liveParent[key] = value
|
liveParent[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-28
@@ -1,8 +1,8 @@
|
|||||||
import { createApp, defineComponent, reactive, inject, markRaw, toRefs, h, customRef, watch, watchEffect } from 'vue'
|
import { createApp, defineComponent, reactive, inject, toRefs, h, watch } from 'vue'
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import Metainfo from '../next/Metainfo.vue'
|
import Metainfo from '../next/Metainfo.vue'
|
||||||
import { createMeta, useMeta } from '../next'
|
import { createMeta, useMeta } from '../next'
|
||||||
import About from './about.vue'
|
// import About from './about.vue'
|
||||||
|
|
||||||
const metaUpdated = 'no'
|
const metaUpdated = 'no'
|
||||||
|
|
||||||
@@ -16,25 +16,24 @@ const ChildComponent = defineComponent({
|
|||||||
<h3>You're looking at the <strong>{{ page }}</strong> page</h3>
|
<h3>You're looking at the <strong>{{ page }}</strong> page</h3>
|
||||||
<p>Has metaInfo been updated due to navigation? {{ metaUpdated }}</p>
|
<p>Has metaInfo been updated due to navigation? {{ metaUpdated }}</p>
|
||||||
</div>`,
|
</div>`,
|
||||||
created () {
|
setup (props) {
|
||||||
// console.log(this)
|
|
||||||
},
|
|
||||||
setup () {
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
date: null,
|
date: null,
|
||||||
metaUpdated
|
metaUpdated
|
||||||
})
|
})
|
||||||
|
|
||||||
const metainfo = useMeta({
|
const title = props.page[0].toUpperCase() + props.page.slice(1)
|
||||||
|
|
||||||
|
useMeta({
|
||||||
charset: 'utf16',
|
charset: 'utf16',
|
||||||
description: 'Description 2',
|
title,
|
||||||
|
description: 'Description ' + props.page,
|
||||||
og: {
|
og: {
|
||||||
title: 'Og Title 2'
|
title: 'Og Title ' + props.page
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
metainfo,
|
|
||||||
...toRefs(state)
|
...toRefs(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +50,7 @@ function view (page) {
|
|||||||
|
|
||||||
const App = {
|
const App = {
|
||||||
setup () {
|
setup () {
|
||||||
/* const metainfo = useMeta({
|
const { meta } = useMeta({
|
||||||
base: { href: '/vue-router', target: '_blank' },
|
base: { href: '/vue-router', target: '_blank' },
|
||||||
charset: 'utf8',
|
charset: 'utf8',
|
||||||
title: 'My Title',
|
title: 'My Title',
|
||||||
@@ -83,7 +82,7 @@ const App = {
|
|||||||
script: [
|
script: [
|
||||||
'<!--[if IE]>',
|
'<!--[if IE]>',
|
||||||
{ src: 'head-script1.js' },
|
{ src: 'head-script1.js' },
|
||||||
'<![endif]>',
|
'<![endif]-->',
|
||||||
{ src: 'body-script2.js', target: 'body' },
|
{ src: 'body-script2.js', target: 'body' },
|
||||||
{ src: 'body-script3.js', target: '#put-it-here' }
|
{ src: 'body-script3.js', target: '#put-it-here' }
|
||||||
],
|
],
|
||||||
@@ -102,21 +101,12 @@ const App = {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(() => (metainfo.title = 'My Updated Title'), 2000) */
|
setTimeout(() => (meta.title = 'My Updated Title'), 2000)
|
||||||
|
|
||||||
const meta = useMeta({
|
|
||||||
charset: 'utf8',
|
|
||||||
title: 'Title 1',
|
|
||||||
og: {
|
|
||||||
title: 'Og Title 1'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
setTimeout(() => (meta.charset = 'utf17'), 2000)
|
|
||||||
setTimeout(() => (meta.og = { title: 'Updated Og Title 1' }), 3000) // TODO: fix
|
|
||||||
|
|
||||||
const metainfo = inject('metainfo')
|
const metainfo = inject('metainfo')
|
||||||
|
|
||||||
|
window.$metainfo = metainfo
|
||||||
|
|
||||||
watch(metainfo, (newValue, oldValue) => {
|
watch(metainfo, (newValue, oldValue) => {
|
||||||
console.log('UPDATE', newValue)
|
console.log('UPDATE', newValue)
|
||||||
})
|
})
|
||||||
@@ -137,7 +127,7 @@ const App = {
|
|||||||
<div id="app">
|
<div id="app">
|
||||||
<h1>vue-router</h1>
|
<h1>vue-router</h1>
|
||||||
<router-link to="/">Home</router-link>
|
<router-link to="/">Home</router-link>
|
||||||
<!-- router-link to="/about">About</router-link -->
|
<router-link to="/about">About</router-link>
|
||||||
<transition name="page" mode="out-in">
|
<transition name="page" mode="out-in">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</transition>
|
</transition>
|
||||||
@@ -146,15 +136,16 @@ const App = {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
function decisionMaker5000000 (options) {
|
function decisionMaker5000000 (key, options, currentValue) {
|
||||||
let theChosenOne
|
let theChosenOne
|
||||||
|
|
||||||
for (const option of options) {
|
for (const option of options) {
|
||||||
if (!theChosenOne || theChosenOne.vm.id < option.vm.id) {
|
if (!theChosenOne || theChosenOne.context.uid < option.context.uid) {
|
||||||
theChosenOne = option
|
theChosenOne = option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(key, currentValue, options.map(({ value }) => value))
|
||||||
console.log(theChosenOne.value)
|
console.log(theChosenOne.value)
|
||||||
return theChosenOne.value
|
return theChosenOne.value
|
||||||
}
|
}
|
||||||
@@ -178,10 +169,16 @@ const router = createRouter({
|
|||||||
history: createWebHistory('/vue-router'),
|
history: createWebHistory('/vue-router'),
|
||||||
routes: [
|
routes: [
|
||||||
{ name: 'home', path: '/', component: view('home') },
|
{ name: 'home', path: '/', component: view('home') },
|
||||||
{ name: 'about', path: '/about', component: About }
|
{ name: 'about', path: '/about', component: view('about') }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useMeta({
|
||||||
|
og: {
|
||||||
|
something: 'test'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
app.component('metainfo', Metainfo)
|
app.component('metainfo', Metainfo)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|||||||
Reference in New Issue
Block a user