petite-vue
为渐进增强优化的Vue子集
petite-vue
是为渐进增强优化的Vue的替代发行版。它提供与标准 Vue 相同的模板语法和反应性思维模型。但是,它专门针对在由服务器框架呈现的现有 HTML 页面上“散布”少量交互进行了优化。查看有关它与标准 Vue 有何不同的更多详细信息。
@vue/reactivity
petite-vue
无需构建步骤即可使用。只需从 CDN 加载它:
<script src="https://unpkg.com/petite-vue" defer init></script>
<!-- anywhere on the page -->
<div v-scope="{ count: 0 }">
{{ count }}
<button @click="count++">inc</button>
</div>
v-scope
标记页面上应由 控制的区域 petite-vue
。defer
属性使脚本在 HTML 内容被解析后执行。init
属性告诉 petite-vue
自动查询和初始化页面上的所有元素 v-scope
。如果您不想要自动初始化,请删除该 init
属性并将脚本移动到末尾 <body>
:
<script src="https://unpkg.com/petite-vue"></script>
<script>
PetiteVue.createApp().mount()
</script>
或者,使用 ES 模块构建:
<script type="module">
import { createApp } from 'https://unpkg.com/petite-vue?module'
createApp().mount()
</script>
简短的 CDN URL 用于原型设计。对于生产使用,使用完全解析的 CDN URL 以避免解析和重定向成本:
https://unpkg.com/petite-vue@0.2.2/dist/petite-vue.iife.js
PetiteVue
全局,支持自动初始化https://unpkg.com/petite-vue@0.2.2/dist/petite-vue.es.js
<script type="module">
该 createApp
函数接受一个数据对象作为所有表达式的根范围。这可用于引导简单的一次性应用程序:
<script type="module">
import { createApp } from 'https://unpkg.com/petite-vue?module'
createApp({
// exposed to all expressions
count: 0,
// getters
get plusOne() {
return this.count + 1
},
// methods
increment() {
this.count++
}
}).mount()
</script>
<!-- v-scope value can be omitted -->
<div v-scope>
<p>{{ count }}</p>
<p>{{ plusOne }}</p>
<button @click="increment">increment</button>
</div>
注意 v-scope
这里不需要有值,只是作为 petite-vue
处理元素的提示。
您可以指定一个挂载目标(选择器或元素)petite-vue
以仅限于页面的该区域:
createApp().mount('#only-this-div')
这也意味着您可以拥有多个 petite-vue
应用程序来控制同一页面上的不同区域:
createApp({
// root scope for app one
}).mount('#app1')
createApp({
// root scope for app two
}).mount('#app2')
您可以监听每个元素的特殊事件 vue:mounted
和生命周期事件(从 v0.4.0 开始需要前缀):vue:unmounted``vue:
<div
v-if="show"
@vue:mounted="console.log('mounted on: ', $el)"
@vue:unmounted="console.log('unmounted: ', $el)"
></div>
v-effect
用于 v-effect
执行反应式内联语句:
<div v-scope="{ count: 0 }">
<div v-effect="$el.textContent = count"></div>
<button @click="count++">++</button>
</div>
效果使用的是响应式数据源,因此每当更改 count
时它都会重新运行。count
另一个替换 todo-focus
原始 Vue TodoMVC 示例中的指令的示例:
<input v-effect="if (todo === editedTodo) $el.focus()" />
“组件”的概念在 中有所不同 petite-vue
,因为它更加简单。
首先,可以使用函数创建可重用范围逻辑:
<script type="module">
import { createApp } from 'https://unpkg.com/petite-vue?module'
function Counter(props) {
return {
count: props.initialCount,
inc() {
this.count++
},
mounted() {
console.log(`I'm mounted!`)
}
}
}
createApp({
Counter
}).mount()
</script>
<div v-scope="Counter({ initialCount: 1 })" @vue:mounted="mounted">
<p>{{ count }}</p>
<button @click="inc">increment</button>
</div>
<div v-scope="Counter({ initialCount: 2 })">
<p>{{ count }}</p>
<button @click="inc">increment</button>
</div>
如果您还想重用一个模板,您可以 $template
在范围对象上提供一个特殊键。该值可以是模板字符串,也可以是 <template>
元素的 ID 选择器:
<script type="module">
import { createApp } from 'https://unpkg.com/petite-vue?module'
function Counter(props) {
return {
$template: '#counter-template',
count: props.initialCount,
inc() {
this.count++
}
}
}
createApp({
Counter
}).mount()
</script>
<template id="counter-template">
My count is {{ count }}
<button @click="inc">++</button>
</template>
<!-- reuse it -->
<div v-scope="Counter({ initialCount: 1 })"></div>
<div v-scope="Counter({ initialCount: 2 })"></div>
建议使用该 <template>
方法而不是内联字符串,因为从本机模板元素克隆更有效。
您可以使用该 reactive
方法(从 重新导出 @vue/reactivity
)来创建全局状态单例:
<script type="module">
import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
const store = reactive({
count: 0,
inc() {
this.count++
}
})
// manipulate it here
store.inc()
createApp({
// share it with app scopes
store
}).mount()
</script>
<div v-scope="{ localCount: 0 }">
<p>Global {{ store.count }}</p>
<button @click="store.inc">increment</button>
<p>Local {{ localCount }}</p>
<button @click="localCount++">increment</button>
</div>
还支持自定义指令,但界面不同:
const myDirective = (ctx) => {
// the element the directive is on
ctx.el
// the raw value expression
// e.g. v-my-dir="x" then this would be "x"
ctx.exp
// v-my-dir:foo -> "foo"
ctx.arg
// v-my-dir.mod -> { mod: true }
ctx.modifiers
// evaluate the expression and get its value
ctx.get()
// evaluate arbitrary expression in current scope
ctx.get(`${ctx.exp} + 10`)
// run reactive effect
ctx.effect(() => {
// this will re-run every time the get() value changes
console.log(ctx.get())
})
return () => {
// cleanup if the element is unmounted
}
}
// register the directive
createApp().directive('my-dir', myDirective).mount()
这是如何 v-html
实现的:
const html = ({ el, get, effect }) => {
effect(() => {
el.innerHTML = get()
})
}
$delimiters
您可以通过传递到根范围来使用自定义分隔符。这在与同样使用胡须的服务器端模板语言一起工作时很有用:
createApp({
$delimiters: ['${', '}']
}).mount()
查看示例目录。
petite-vue
只要v-scope
v-effect
@vue:mounted
&@vue:unmounted
活动$el
指向指令绑定到的当前元素(而不是组件根元素)createApp()
接受全局状态而不是组件{{ }}
文本绑定(可使用自定义分隔符配置)v-bind
(包括 :
速记和类/样式特殊处理)v-on
(包括 @
速记和所有修饰语)v-model
(所有输入类型 + 非字符串 :value
绑定)v-if
// v-else
_v-else-if
v-for
v-show
v-html
v-text
v-pre
v-once
v-cloak
reactive()
nextTick()
一些特征被丢弃,因为它们在渐进增强的背景下具有相对较低的效用/大小比率。如果你需要这些特性,你可能应该只使用标准的 Vue。
ref()
等 computed()
。petite-vue
没有虚拟 DOM)v-for
深度解构v-on="object"
v-is
&<component :is="xxx">
v-bind:style
自动加前缀的重点 petite-vue
不仅仅是小。它是关于为预期的用例使用最佳实现(渐进增强)。
标准 Vue 可以在有或没有构建步骤的情况下使用。当使用构建设置(例如,使用单文件组件)时,我们会预编译所有模板,因此在运行时无需进行模板处理。由于 tree-shaking,我们可以在标准 Vue 中提供可选功能,在不使用时不会增加你的包大小。这是标准 Vue 的最佳用法,但由于它涉及构建设置,因此更适合构建具有相对繁重交互的 SPA 或应用程序。
当使用没有构建步骤并安装到 DOM 内模板的标准 Vue 时,它的优化程度要低得多,因为:
petite-vue
通过遍历现有的 DOM 并直接将细粒度的反应效果附加到元素来避免所有这些开销。DOM是模板。这意味着 petite-vue
在渐进增强场景中效率更高。
这也是 Vue 1 的工作方式。这里的权衡是这种方法与 DOM 耦合,因此不适合与平台无关的渲染或 JavaScript SSR。我们也失去了使用渲染函数进行高级抽象的能力。但是,正如您可能知道的那样,在渐进增强的情况下很少需要这些功能。
petite-vue
确实解决了与Alpine类似的范围,但目标是 (1) 更小和 (2) 与 Vue 更兼容。
petite-vue
大约是alpine的一半大小。petite-vue
没有过渡系统(也许这可以是一个可选插件)。petite-vue
将尽可能与标准 Vue 行为保持一致,以便在需要时减少迁移到标准 Vue 的摩擦。它旨在成为 Vue 生态系统的一部分, 以涵盖标准 Vue 对当今的优化程度较低的渐进增强用例。petite-vue
计算模板中的 JavaScript 表达式。这意味着如果 petite-vue
安装在 DOM 的某个区域上,该区域包含来自用户数据的未经处理的 HTML,则可能会导致 XSS 攻击。 如果您的页面呈现用户提交的 HTML,您应该更喜欢 petite-vue
使用显式安装目标进行初始化,以便它只处理由您控制的部分 。您还可以清理任何用户提交的 v-scope
属性 HTML。
petite-vue
使用 计算表达式 new Function()
,这可能在严格的 CSP 设置中被禁止。没有计划提供 CSP 构建,因为它涉及交付一个表达式解析器,这违背了轻量级的目的。如果您有严格的 CSP 要求,您可能应该使用标准 Vue 并预编译模板。
MIT