如何在访问 Vue 实例时动态生成计算道具?
How to generate computed props on the fly while accessing the Vue instance?
我想知道是否有一种方法可以以编程方式创建计算道具,同时仍然访问实例以实现 动态值
类似的东西(this
下面未定义)
<script>
export default {
computed: {
...createDynamicPropsWithTheContext(this), // helper function that returns an object
}
}
</script>
关于这个问题,Linus给出了一个解决方案:https://forum.vuejs.org/t/generating-computed-properties-on-the-fly/14833/4看起来像
computed: {
...mapPropsModels(['cool', 'but', 'static'])
}
这工作正常,但主要问题是它是完全静态的。例如,有没有办法访问 Vue 实例以获取道具?
更多上下文
出于测试目的,我的辅助函数非常简单
export const createDynamicPropsWithTheContext = (listToConvert) => {
return listToConvert?.reduce((acc, curr) => {
acc[curr] = curr
return acc
}, {})
}
我实际上希望传递给这个辅助函数(通过 this
)的是与特定前缀匹配的道具,也就是以任何 is|can|has|show
开头的道具(我使用的是正则表达式),我确实可以通过经典 parent/child 状态传输中的 this.$options.props
进行访问。
我的问题的最终想法主要是避免像 ...createDynamicPropsWithTheContext(['canSubmit', 'showModal', 'isClosed'])
那样手动编写所有道具,而是以编程方式填充它们(很多组件都需要这种模式)。
props是这样传递的
<my-component can-submit="false" show-modal="true" />
PS:它是 can-submit
而不是 :can-submit
故意的(虽然现在仍然被黑进了 falsy
结果!)。
这是为了方便最终用户使用,不需要记住前缀 :
,是的,我知道......对于一个可以遵循 Vue 约定的分号来说有很多困难。
您可以使用 setup()
挂钩,它接收 props
作为第一个参数。将 props
参数传递给 createDynamicPropsWithTheContext
,并将结果传播到 setup()
的 return(就像您之前在 computed
选项中所做的那样):
import { createDynamicPropsWithTheContext } from './props-utils'
export default {
⋮
setup(props) {
return {
...createDynamicPropsWithTheContext(props),
}
}
}
如果整个事情都是为了避免使用 :
,那么您可能要考虑使用一个简单的对象(或对象数组)作为数据源。您可以遍历列表并将数据绑定到生成的组件。在这种情况下,唯一使用的 :
是在对象
中
const comps = [{
"can-submit": false,
"show-modal": true,
"something-else": false,
},
{
"can-submit": true,
"show-modal": true,
"something-else": false,
},
{
"can-submit": false,
"show-modal": true,
"something-else": true,
},
]
const CustomComponent = {
setup(props, { attrs }) {
return {
attrs
}
},
template: `
<div
v-bind="attrs"
>{{ attrs }}</div>
`
}
const vm = Vue.createApp({
setup() {
return {
comps
}
},
template: `
<custom-component
v-for="(item, i) in comps"
v-bind="item"
></custom-component>
`
})
vm.component('CustomComponent', CustomComponent)
vm.mount('#app')
<script src="https://unpkg.com/vue@3"></script>
<div id="app">{{ message }}</div>
感谢 Vue's Discord Cathrine
和 skirtle
的朋友们,我终于成功了!
这是对我有帮助的 the thread and here is the SFC example,尤其是这段代码
created () {
const magicIsShown = computed(() => this.isShown === true || this.isShown === 'true')
Object.defineProperty(this, 'magicIsShown', {
get () {
return magicIsShown.value
}
})
}
使用 Object.defineProperty(this...
有助于保持整个状态的反应性,并且 computed(() =>
可以引用其他一些道具(我正在查看我的案例)。
使用 JS 对象是可行的,但我必须从模板中完成它(这是一个较低的进入门槛)。
不过,这是我想出的解决方案,作为在每个组件中导入的全局 mixin。
// helper functions
const proceedIfStringlean = (propName) => /^(is|can|has|show)+.*/.test(propName)
const stringleanCase = (string) => 'stringlean' + string[0].toUpperCase() + string.slice(1)
const computeStringlean = (value) => {
if (typeof value == 'string') {
return value == 'true'
}
return value
}
// the actual mixin
const generateStringleans = {
created() {
for (const [key, _value] of Object.entries(this.$props)) {
if (proceedIfStringlean(key)) {
const stringleanComputed = computed(() => this[key])
Object.defineProperty(this, stringleanCase(key), {
get() {
return computeStringlean(stringleanComputed.value)
},
// do not write any `set()` here because this is just an overlay
})
}
}
},
}
这将扫描每个 .vue
组件,获取传递的道具,如果这些道具以 is|can|has|show
为前缀,将创建一个重复的 counter-part,前缀为 stringlean
+ 将初始道具传递给方法(在我的例子中为 computeStringlean
)。
效果很好,因为我们直接在 vanilla JS 中连接它,所以没有预期的 devtools 支持。
我想知道是否有一种方法可以以编程方式创建计算道具,同时仍然访问实例以实现 动态值
类似的东西(this
下面未定义)
<script>
export default {
computed: {
...createDynamicPropsWithTheContext(this), // helper function that returns an object
}
}
</script>
关于这个问题,Linus给出了一个解决方案:https://forum.vuejs.org/t/generating-computed-properties-on-the-fly/14833/4看起来像
computed: {
...mapPropsModels(['cool', 'but', 'static'])
}
这工作正常,但主要问题是它是完全静态的。例如,有没有办法访问 Vue 实例以获取道具?
更多上下文
出于测试目的,我的辅助函数非常简单
export const createDynamicPropsWithTheContext = (listToConvert) => {
return listToConvert?.reduce((acc, curr) => {
acc[curr] = curr
return acc
}, {})
}
我实际上希望传递给这个辅助函数(通过 this
)的是与特定前缀匹配的道具,也就是以任何 is|can|has|show
开头的道具(我使用的是正则表达式),我确实可以通过经典 parent/child 状态传输中的 this.$options.props
进行访问。
我的问题的最终想法主要是避免像 ...createDynamicPropsWithTheContext(['canSubmit', 'showModal', 'isClosed'])
那样手动编写所有道具,而是以编程方式填充它们(很多组件都需要这种模式)。
props是这样传递的
<my-component can-submit="false" show-modal="true" />
PS:它是 can-submit
而不是 :can-submit
故意的(虽然现在仍然被黑进了 falsy
结果!)。
这是为了方便最终用户使用,不需要记住前缀 :
,是的,我知道......对于一个可以遵循 Vue 约定的分号来说有很多困难。
您可以使用 setup()
挂钩,它接收 props
作为第一个参数。将 props
参数传递给 createDynamicPropsWithTheContext
,并将结果传播到 setup()
的 return(就像您之前在 computed
选项中所做的那样):
import { createDynamicPropsWithTheContext } from './props-utils'
export default {
⋮
setup(props) {
return {
...createDynamicPropsWithTheContext(props),
}
}
}
如果整个事情都是为了避免使用 :
,那么您可能要考虑使用一个简单的对象(或对象数组)作为数据源。您可以遍历列表并将数据绑定到生成的组件。在这种情况下,唯一使用的 :
是在对象
const comps = [{
"can-submit": false,
"show-modal": true,
"something-else": false,
},
{
"can-submit": true,
"show-modal": true,
"something-else": false,
},
{
"can-submit": false,
"show-modal": true,
"something-else": true,
},
]
const CustomComponent = {
setup(props, { attrs }) {
return {
attrs
}
},
template: `
<div
v-bind="attrs"
>{{ attrs }}</div>
`
}
const vm = Vue.createApp({
setup() {
return {
comps
}
},
template: `
<custom-component
v-for="(item, i) in comps"
v-bind="item"
></custom-component>
`
})
vm.component('CustomComponent', CustomComponent)
vm.mount('#app')
<script src="https://unpkg.com/vue@3"></script>
<div id="app">{{ message }}</div>
感谢 Vue's Discord Cathrine
和 skirtle
的朋友们,我终于成功了!
这是对我有帮助的 the thread and here is the SFC example,尤其是这段代码
created () {
const magicIsShown = computed(() => this.isShown === true || this.isShown === 'true')
Object.defineProperty(this, 'magicIsShown', {
get () {
return magicIsShown.value
}
})
}
使用 Object.defineProperty(this...
有助于保持整个状态的反应性,并且 computed(() =>
可以引用其他一些道具(我正在查看我的案例)。
使用 JS 对象是可行的,但我必须从模板中完成它(这是一个较低的进入门槛)。
不过,这是我想出的解决方案,作为在每个组件中导入的全局 mixin。
// helper functions
const proceedIfStringlean = (propName) => /^(is|can|has|show)+.*/.test(propName)
const stringleanCase = (string) => 'stringlean' + string[0].toUpperCase() + string.slice(1)
const computeStringlean = (value) => {
if (typeof value == 'string') {
return value == 'true'
}
return value
}
// the actual mixin
const generateStringleans = {
created() {
for (const [key, _value] of Object.entries(this.$props)) {
if (proceedIfStringlean(key)) {
const stringleanComputed = computed(() => this[key])
Object.defineProperty(this, stringleanCase(key), {
get() {
return computeStringlean(stringleanComputed.value)
},
// do not write any `set()` here because this is just an overlay
})
}
}
},
}
这将扫描每个 .vue
组件,获取传递的道具,如果这些道具以 is|can|has|show
为前缀,将创建一个重复的 counter-part,前缀为 stringlean
+ 将初始道具传递给方法(在我的例子中为 computeStringlean
)。
效果很好,因为我们直接在 vanilla JS 中连接它,所以没有预期的 devtools 支持。