Svelte vs Vue 
官网地址
Vue: cn.vuejs.org/
Svelte: svelte.dev/
是什么
什么是Vue
Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。
什么是 Svelte?
Svelte 是一个构建 web 应用程序的工具。
Svelte 与诸如 React 和 Vue 等 JavaScript 框架类似,都怀揣着一颗让构建交互式用户界面变得更容易的心。
但是有一个关键的区别:Svelte 在 构建/编译阶段 将你的应用程序转换为理想的 JavaScript 应用,而不是在 运行阶段 解释应用程序的代码。这意味着你不需要为框架所消耗的性能付出成本,并且在应用程序首次加载时没有额外损失。
下载量
从下图可以看到目前vue的下载量存在量级的差别
Svelte比Vue快和小
- Vue
- Svelte
UI框架:
- Vue框架的UI框架有许多选择,以下是一些常见的UI框架:
- Element UI:一款由饿了么团队开发的成熟的UI框架。
- Vuetify:一个基于Material Design的Vue组件库。
- Ant Design Vue:一个基于Ant Design设计语言的Vue组件库。
- BootstrapVue:是对Bootstrap框架的Vue封装,提供了一套响应式的UI组件。
- Buefy:一个基于Bulma CSS框架和Vue的UI组件库。
- Quasar:一个全能的Vue框架,包含了一套完整的UI组件和工具集。
- Muse-UI:一个优雅的、基于Material Design的Vue UI框架。
- iView:一套基于Vue的高质量UI组件库。
- Tailwind CSS:一个高度可定制的CSS框架,可以与Vue无缝整合。
- Svelte框架相比Vue框架而言,由于其独特的编译方式,UI框架的选择相对较少。以下是一些适用于Svelte框架的UI框架:
- Carbon:由IBM开发的一套通用UI组件库,提供了一系列现代化的UI组件和样式。
- Sveltestrap:一个基于Bootstrap的Svelte组件库,提供了一套简洁而强大的UI组件。
- Smelte:一个基于Material Design的Svelte组件库,提供了一套漂亮的UI组件和样式。
- Svelte Material UI:一个致力于将Material Design引入到Svelte中的UI组件库。
- Svelteify:一个基于Tailwind CSS的Svelte组件库,提供了一套响应式的UI组件和样式。
开始
1. 文件名
- Vue
文件以后缀.vue命名
- Svelte
文件以后缀.svelte命名
2. 语法格式
- Vue
<script setup>
操作...
</script>
<template>
视图...
</template>
<style>
全局...
</style>
<style scope>
局部...
</style>
- Svelte
默认style只影响当前组件;
需要设置全局css可以用
:global(...)标记
<script>
操作...
</script>
视图...
<style>
局部...
p {
color: #1893fe;
}
/* 全局 */
div :global(strong) {
/* 这里表示全局应用于被<div>包裹的<strong>标签 */
color: goldenrod;
}
</style>
3. 组件
- Vue
- 声明 一个
Component.vue的文件,在里面处理视图和逻辑 - 引入
<script setup>
import Component from './Component.vue'
</script>
<template>
<Component></Component>
</template>
- Svelte
- 声明 一个
Component.Svelte的文件,在里面处理视图和逻辑 - 引入
<script>
import Component from './Component.Svelte'
</script>
<Component></Component>
4. HTML标记
- Vue
<script setup>
const string = `here's some <strong>HTML!!!</strong>`;
</script>
<!-- 使用v-html标记 -->
<p v-html="string"></p>
- Svelte
<script>
let string = `here's some <strong>HTML!!!</strong>`;
</script>
<!-- 使用@html标记 -->
<p>{@html string}</p>
5. 响应式数据
- Vue
<script setup>
import {ref, reactive} from 'vue'
const count = ref(0)
const handleClick = () => {
count.value += 1
}
</script>
<template>
{{ count }}
<button @click="handleClick">
点我 {{ count }}
</button>
</template>
- Svelte
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count}
{count === 1 ? 'time' : 'times'}
</button>
6. 计算属性
- Vue
引入
computed进行计算
<script setup>
import { computed, ref } from 'vue'
const count = ref(1)
const doubleCount = computed(() => {
return count.value * 2
})
const handleClick = () => {
count.value += 1
}
</script>
<template>
<button @click="handleClick">点我{{ count }}</button>
结果:{{ doubleCount }}
</template>
- Svelte
引入
$:进行计算
<script>
let count = 1
$: doubleCount = count * 2
function handleClick() {
count += 1
}
</script>
<button on:click={handleClick}>点我{count}</button>
count * 2 = {doubleCount}
7. 动态数据监听
- Vue
<script setup>
import { watch, ref } from 'vue'
let count = ref(0)
watch(count, () => {
if (count.value > 9) {
count.value = 9
alert('count is dangerously high!')
}
})
function handleCick() {
count.value += 1
}
</script>
<template>
<button @click="handleCick">点我 {{ count }}</button
>{{ count >= 9 ? 'count is dangerously high!' : count }}
</template>
- Svelte
<script>
let count = 0
$: if (count > 9) {
count = 9
alert(`count is dangerously high!`)
}
function handleCick() {
count += 1;
}
</script>
<button on:click={handleCick}>点我 {count}</button> {count >= 9 ? "count is dangerously high!" : count}
8. Props 外部传入的值
- Vue
- 使用
defineProps()标记外部传入的属性名;- 在组件中使用
:属性名="值"赋值;- 也可以默认当前属性的值;
// Compontent 组件声明属性
// defineProps(['receiveCount'])
defineProps({
receiveCount: Number,
receiveStr: {
type: String,
default: 'is a string',
},
})
// App组件中引入 Compontent组件
<Compontent :receiveCount="99" ></Compontent>
- Svelte
- 使用
export let name标记外部传入的属性名;- 在组件中使用
对象名={值}赋值;- 可以默认当前属性的值;
// Compontent 组件声明属性
export let receiveCount;
export let receiveStr = 'is a string'
// App组件中引入 Compontent组件
<Compontent receiveCount={99}></Compontent>
9. If语句
- Vue
在标签中使用
v-if="条件1"决定当前内容是否显示,可以直接接着写入v-else-if=" 条件2"或者v-else来判断显示其他内容
<div v-if="count < 3">我是count小于3的时候显示的</div>
<div v-else-if="count >= 3 && count <= 6">
我是count 大于等于 3 并且 小于等于 6的时候显示的
</div>
<div v-else>我是不符合的时候显示的</div>
- Svelte
- 首先使用
{#if 条件1}标记判断开始,使用{/if }标记判断结束;在标记中间显示内容- 可以在
{#if 条件1}{/if}中间可以使用{:else }或者{:else if 条件3}来依次判断内容显示
{#if count < 3}
<p>我是count小于3的时候显示的</p>
{:else if count >= 3 && count <= 6}
<p>我是count 大于等于 3 并且 小于等于 6的时候显示的</p>
{:else}
<p>我是不符合的时候显示的</p>
{/if}
10 循环
- Vue
- 在被循环的节点上使用
v-for="元素对象 in 元素数组"- 循环创建的节点是需要添加唯一标志的,这里的唯一标志是通过在节点上添加
:key="唯一标志"来标记的
<script setup>
let cats = [
{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
{ id: 'z_AbfPXTKms', name: 'Maru' },
{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' },
]
</script>
<template>
<ul>
<li v-for="{id, name} in cats" :key="id">
{{ name }}的id是:{{ id }}
</li>
</ul>
</template>
- Svelte
- 在要循环的节点外围使用
{#each 元素数组 as 元素 (唯一标识)} {/each}标记包含住,然后在标记内写入要循环的节点- 这里注意Each循环需要添加一个唯一标志,这里的唯一标志是在
{#each 元素数组 as 元素 (唯一标识)}标记的开始处使用
<script>
let cats = [
{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
{ id: 'z_AbfPXTKms', name: 'Maru' },
{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' },
]
</script>
<ul>
{#each cats as { id, name } (id)}
<li>
{name}的id是:{id}
</li>
{/each}
</ul>
11. #await的不同状态
- Vue
v-loading=loading
- Svelte
#await可以监听到一个异步的变量状态:pending、fulfilled和rejected;
#await有多种使用1. 监听pending、fulfilled、rejected三种状态 {#await expression}...{:then name}...{:catch name}...{/await} 2. 监听pending、fulfilled {#await expression}loading...{:then name}...{/await} 3. 监听fulfilled {#await expression then name}...{/await} 4. 监听rejected {#await expression catch name}...{/await}
<script>
let request = loadData()
/**
* 开始网络请求
*/
async function loadData() {
const res = await sleep()
return res
}
/**
* 模拟网络请求
*/
function sleep() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const count = Math.ceil(Math.random() * 10)
count % 2 ? resolve(count) : reject('error')
}, 2e3)
})
}
function handleClick() {
request = loadData()
}
</script>
<button on:click={handleClick}>开始网络请求</button>
{#await request}
<p>loading....</p>
{:then name}
<p>value的值是:{name}</p>
{:catch}
<p>哎呀出错了</p>
{/await}
12. Event
- Vue
- 使用
v-on:事件名和@事件名都可以给标签绑定事件- 在事件名后添加
.事件限制,@click.once
<script setup>
import { reactive } from 'vue'
const m = reactive({
x: 0,
y: 0,
})
function handleMove(event) {
m.x = event.clientX
m.y = event.clientY
}
function handleClick() {
alert('only can click once!')
}
</script>
<template>
<div class="box" v-on:mousemove="handleMove" @click.once="handleClick">
The mouse position is {{ m.x }} x {{ m.y }}
</div>
</template>
<style scoped>
.box {
width: 100%;
height: 100px;
border: 1px solid #ccc;
}
</style>
- Svelte
- 使用
on:事件名给标签绑定事件- 在事件名后添加
|事件限制,on:click|once
<script>
let m = {
x: 0,
y: 0,
}
function handleMove(event) {
m.x = event.clientX
m.y = event.clientY
}
function handleClick() {
alert('only can click once!')
}
</script>
<div class="box" on:mousemove={handleMove} on:click|once={handleClick}>
The mouse position is {m.x} x {m.y}
</div>
<style>
.box {
width: 100%;
height: 100px;
border: 1px solid #ccc;
}
</style>
12.1 子向父传递数据
- Vue
- 子组件,创建和分发事件
使用
defineEmits注册事件,在特定情况下触发事件传递数据
<script setup>
const emits = defineEmits(['message'])
function handleMessageBtn() {
emits('message', { text: 'hello, i am message' })
}
</script>
<template>
<button @click="handleMessageBtn">message btn</button>
</template>
- 父组件接收数据和响应事件
在添加子组件的地方使用
@事件名=响应事件
<script setup>
import { reactive, ref } from 'vue'
import EventChildComponent from './EventChildComponent.vue'
const message = ref('')
function handleMessageClick(value) {
message.value = value?.text
alert(message.value)
}
</script>
<template>
<EventChildComponent @message="handleMessageClick"></EventChildComponent>
</template>
- Svelte
- 子组件
使用
createEventDispatcher创建事件分发器,在特定的情况下触发事件传递数据
<script>
import { createEventDispatcher } from 'svelte'
// 创建事件分发器
const dispatch = createEventDispatcher()
function handleMessageBtn() {
dispatch('message', {
text: 'hello, i am message',
})
}
</script>
<button on:click={handleMessageBtn}>message btn</button>
- 父组件
在添加子组件的地方使用
on:事件名={响应事件}
<script>
import EventChildComponent from './EventChildComponent.svelte'
let message = ''
function handleMessageClick(event) {
console.log(event)
// event.detail 表示分发出来的数据
message = event?.detail?.text
alert(message)
}
</script>
<EventChildComponent on:message={handleMessageClick} />
12.2 孙子组件向上传递数据
- Vue
使用
provide为后代提供一个key和值,值可以是变量、常量或回调事件;使用
inject接收祖先组件注入的key和值,并返回一个对象
- 祖先组件
<script setup>
import { provide } from 'vue'
provide('gradesun-message', (val) => {
alert(val)
})
</script>
- 后代组件
<script setup>
import { inject } from 'vue'
const gradesunFunc = inject('gradesun-message')
function handleClickCC() {
gradesunFunc('我是孙子组件')
}
</script>
<template>
<button @click="handleClickCC">gradesun btn</button>
</template>
- Svelte
使用
getContext和setContext设置和获取上下文来进行跨组件通信
- 祖先组件
<script>
import { setContext } from 'svelte'
import EventChildComponent from './EventChildComponent.svelte'
setContext('p-message', '我是老祖')
setContext('p-fun',(obj) => {
console.log(obj)
})
</script>
<EventChildComponent />
- 子组件组件
<script>
import { getContext } from 'svelte'
const pMsg = getContext('p-message')
const pFun = getContext('p-fun')
</script>
{pMsg}
<button on:click={() => pFun('123')}>
gradesun btn
</button>
12.3 自定义事件,并在外部实现
- Vue
使用
defineEmits()声明事件名,在特定情况下响应
<script setup>
// 声明
const emits = defineEmits(['message'])
function handleClick () {
// 响应
emits('message')
}
</script>
<template>
<button @click="handleClick">
click
</button>
</template>
- Svelte
需要使用
on:事件名进行标记
- 子组件
<button on:click>click me</button>
- 父组件
<script>
import DomEventForwardingComponent from '../components/DomEventForwardingComponent.svelte'
function handleClickDomEvent () {
console.log(123);
}
</script>
<DomEventForwardingComponent on:click={handleClickDomEvent}></DomEventForwardingComponent>
13. Bindings
数据双向绑定实现了视图影响数据,数据也影响视图。
- Vue
实现双向绑定简单的说就是使用
v-on监听变化,v-bind绑定数据。提供了一个语法糖:
v-model
<script setup>
import { ref } from 'vue'
const name = ref('')
const scoops = ref(1)
</script>
<template>
<input v-model="name" type="text" placeholder="请输入内容" />
<p>Hello {{ name || 'Vue' }}!</p>
<!-- 多选 -->
<label>
<input type="radio" :value="1" />
One scoop
</label>
<label>
<input type="radio" v-model="scoops" :value="2" />
Two scoops
</label>
<p>scoops 的值是: {{ scoops }}</p>
</template>
- Svelte
它的元素指令有很多,参考Element directives
<script>
let name = ''
let scoops = 1
</script>
<input bind:value={name} type="text" placeholder="请输入内容" />
<p>Hello {name || 'Svelte'}!</p>
<!-- 多选 bind:group -->
<label>
<input type="radio" bind:group={scoops} value={1} />
One scoop
</label>
<label>
<input type="radio" bind:group={scoops} value={2} />
Two scoops
</label>
<p>scoops 的值是: {scoops}</p>
13.1 bind:this == ?
- Vue
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const canvas = ref(null)
const frame = ref(null)
onMounted(() => {
const ctx = canvas.value.getContext('2d')
;(function loop() {
console.log(1)
frame.value = requestAnimationFrame(loop)
const imageData = ctx.getImageData(
0,
0,
canvas.value.width,
canvas.value.height
)
for (let p = 0; p < imageData.data.length; p += 4) {
const i = p / 4
const x = i % canvas.value.width
const y = (i / canvas.value.height) >>> 0
const t = window.performance.now()
const r = 64 + (128 * x) / canvas.value.width + 64 * Math.sin(t / 1000)
const g = 64 + (128 * y) / canvas.value.height + 64 * Math.cos(t / 1400)
const b = 128
imageData.data[p + 0] = r
imageData.data[p + 1] = g
imageData.data[p + 2] = b
imageData.data[p + 3] = 255
}
ctx.putImageData(imageData, 0, 0)
})()
})
onUnmounted(() => {
console.log(2)
cancelAnimationFrame(frame.value)
})
</script>
<template>
<canvas ref="canvas"></canvas>
</template>
<style scoped>
canvas {
width: 100%;
height: 100%;
background-color: #666;
-webkit-mask: url(/src/assets/svelte-logo-mask.svg) 50% 50% no-repeat;
mask: url(/src/assets/svelte-logo-mask.svg) 50% 50% no-repeat;
}
</style>
- Svelte
<script>
import { onMount } from 'svelte'
let canvas
onMount(() => {
console.log(canvas)
const ctx = canvas.getContext('2d')
let frame
;(function loop() {
frame = requestAnimationFrame(loop)
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
for (let p = 0; p < imageData.data.length; p += 4) {
const i = p / 4
const x = i % canvas.width
const y = (i / canvas.height) >>> 0
const t = window.performance.now()
const r = 64 + (128 * x) / canvas.width + 64 * Math.sin(t / 1000)
const g = 64 + (128 * y) / canvas.height + 64 * Math.cos(t / 1400)
const b = 128
imageData.data[p + 0] = r
imageData.data[p + 1] = g
imageData.data[p + 2] = b
imageData.data[p + 3] = 255
}
ctx.putImageData(imageData, 0, 0)
})()
return () => {
cancelAnimationFrame(frame)
}
})
</script>
dom
<canvas bind:this={canvas} />
<style>
canvas {
width: 100%;
height: 100%;
background-color: #666;
-webkit-mask: url(/src/lib/images/svelte-logo-mask.svg) 50% 50% no-repeat;
mask: url(/src/lib/images/svelte-logo-mask.svg) 50% 50% no-repeat;
}
</style>
13.2 Component !
- Vue
- 子组件
Keypad
<script setup>
import { defineExpose, ref } from 'vue'
const emits = defineEmits(['submit'])
const password = ref('')
const select = (val) => {
password.value += val
}
const handleClear = () => {
password.value = ''
}
const handleSubmit = () => {
emits('submit')
}
defineExpose({
password,
})
</script>
<template>
<div class="keypad">
<button @click="select(1)">1</button>
<button @click="select(2)">2</button>
<button @click="select(3)">3</button>
<button @click="select(4)">4</button>
<button @click="select(5)">5</button>
<button @click="select(6)">6</button>
<button @click="select(7)">7</button>
<button @click="select(8)">8</button>
<button @click="select(9)">9</button>
<button :disabled="!password" @click="handleClear">clear</button>
<button @click="select(0)">0</button>
<button :disabled="!password" @click="handleSubmit">submit</button>
</div>
</template>
<style scoped>
.keypad {
display: grid;
grid-template-columns: repeat(3, 5em);
grid-template-rows: repeat(4, 3em);
grid-gap: 0.5em;
}
button {
margin: 0;
}
</style>
- 父组件
ComponentComponent
<script setup>
import { ref, watch } from 'vue'
import Keypad from './Keypad.vue'
const keypad = ref(null)
const pin = ref('')
watch(
() => keypad.value?.password,
(newVal) => {
pin.value = newVal ? newVal.replace(/\d(?!$)/g, '•') : 'enter your pin'
},
{ immediate: true, deep: true }
)
function handleSubmit() {
alert(`submitted ${keypad.value?.password}`)
}
</script>
<template>
<h1 :class="{ pin: keypad?.password }">{{ pin }}</h1>
<Keypad ref="keypad" @submit="handleSubmit"></Keypad>
</template>
<style>
h1 {
color: #ccc;
}
h1.pin {
color: #333;
}
:global(body.dark) h1 {
color: #444;
}
:global(body.dark) h1.pin {
color: #fff;
}
</style>
- Svelte
- 父组件
ComponentComponent
<script>
import Keypad from './Keypad.svelte'
let pin
$: view = pin ? pin.replace(/\d(?!$)/g, '•') : 'enter you pin'
function handleSubmit() {
alert(pin)
}
</script>
<h1 class:pin>{view}</h1>
<Keypad bind:value={pin} on:submit={handleSubmit} />
<style>
h1 {
color: #ccc;
}
h1.pin {
color: #333;
}
:global(body.dark) h1 {
color: #444;
}
:global(body.dark) h1.pin {
color: #fff;
}
</style>
- 子组件
Keypad
<script>
import { createEventDispatcher } from 'svelte'
export let value = ''
const dispatch = createEventDispatcher()
const select = (num) => () => (value += num)
const clear = () => (value = '')
const submit = () => dispatch('submit')
</script>
<div class="keypad">
<button on:click={select(1)}>1</button>
<button on:click={select(2)}>2</button>
<button on:click={select(3)}>3</button>
<button on:click={select(4)}>4</button>
<button on:click={select(5)}>5</button>
<button on:click={select(6)}>6</button>
<button on:click={select(7)}>7</button>
<button on:click={select(8)}>8</button>
<button on:click={select(9)}>9</button>
<button disabled={!value} on:click={clear}>clear</button>
<button on:click={select(0)}>0</button>
<button disabled={!value} on:click={submit}>submit</button>
</div>
<style>
.keypad {
display: grid;
grid-template-columns: repeat(3, 5em);
grid-template-rows: repeat(4, 3em);
grid-gap: 0.5em;
}
button {
margin: 0;
}
</style>
14 tick
一个可以立刻更新DOM的方法
- Vue
<script setup>
import { ref, nextTick } from 'vue'
const text = ref('Select some text and hit the tab key to toggle uppercase')
function handleKeyDown(event) {
if (event?.key !== 'Tab') return
if (event.target) {
const { selectionStart, selectionEnd, value } = event.target
const selection = value.slice(selectionStart, selectionEnd)
const replacement = /[a-z]/.test(selection)
? selection.toUpperCase()
: selection.toLowerCase()
text.value =
value.slice(0, selectionStart) + replacement + value.slice(selectionEnd)
nextTick(() => {
event.target.selectionStart = selectionStart
event.target.selectionEnd = selectionEnd
})
}
}
</script>
<template>
<textarea v-model="text" @keydown.prevent="handleKeyDown"></textarea>
</template>
<style scoped>
textarea {
width: 100%;
height: 200px;
}
</style>
- Svelete
<script>
import { tick } from 'svelte'
let text = 'Select some text and hit the tab key to toggle uppercase'
function handleKeyDown(event) {
if (event?.key !== 'Tab') return
if (event.target) {
const { selectionStart, selectionEnd, value } = event.target
const selection = value.slice(selectionStart, selectionEnd)
const replacement = /[a-z]/.test(selection)
? selection.toUpperCase()
: selection.toLowerCase()
text =
value.slice(0, selectionStart) + replacement + value.slice(selectionEnd)
tick().then(() => {
event.target.selectionStart = selectionStart
event.target.selectionEnd = selectionEnd
})
}
}
</script>
<textarea bind:value={text} on:keydown|preventDefault={handleKeyDown} />
<style>
textarea {
width: 100%;
height: 200px;
}
</style>
15 stores
- Vue
- 下载
npm install pinia - 在入口函数处创建
import { createPinia } from 'pinia'
app.use(createPinia())
- 创建仓库
userInfo,注意导入并使用defineStore
import { defineStore } from 'pinia'
export const useUserInfo = defineStore('userInfoStore', {
state () {
return {
info: null
}
},
getters: {
// 获取id
userId (state) {
return state?.id
},
// 获取用户名
userName (state) {
return state?.name
}
},
actions: {
/**
* 设置用户数据
* @param {Object} obj 用户数据
*/
setInfo (obj) {
obj && (this.info = obj)
},
/**
* 设置用户数据
* @param {string} key 键名
* @param {any} value 数据
*/
changeInfo (key, value) {
key && value && (this.info[key] = value)
}
}
})
- 在组件中使用
<script setup>
import { useUserInfo } from '../stores/index.store'
const userInfo = useUserInfo()
function handleSetInfo() {
// userInfo.info = {
// id: 1,
// gender: '男',
// name: 'AI',
// age: 18,
// info: '吊炸天',
// }
userInfo.setInfo({
id: 1,
gender: '男',
name: 'AI',
age: 18,
info: '吊炸天',
})
}
function handleChangeInfo() {
// userInfo.info['name'] = 'AI'
userInfo.changeInfo('name', 'AI')
}
</script>
<template>
<ul>
<template v-if="userInfo.info">
<li v-for="key in Object.keys(userInfo.info)" :key="key">
{{ key }}: {{ userInfo.info[key] }}
</li>
</template>
</ul>
<button @click="handleSetInfo">setInfo</button>
<button @click="handleChangeInfo">changeInfo</button>
</template>
- Svelte
writable, readable, get, derived
- 创建仓库,引入
svelte/store并使用writable
import { writable } from 'svelte/store'
/**
* 创建用户资料仓库
*/
function createUserInfo () {
const { subscribe, set, update } = writable(null)
/**
* 赋值用户资料
* @param {Object} obj 对象
*/
function setInfo (obj) {
obj && set(obj)
}
/**
* 更新用户资料
* @param {string} key 更新的字段名
* @param {any} value 更新的值
*/
function updateInfo (key, value) {
update((info) => {
info && info.hasOwnProperty([key]) && value && (info[key] = value)
return info
})
}
return { subscribe, setInfo, updateInfo }
}
export const userInfo = createUserInfo()
- 在组件中使用
<script>
import { userInfo } from '@/store/index.Store.js'
// 用户资料
function handleSetInfo() {
userInfo.setInfo({
id: 1,
gender: '男',
name: 'shutong',
age: 18,
info: '帅哥',
})
}
function handleUpdateInfo() {
userInfo.updateInfo('age', 20)
}
</script>
<!-- 用户资料 -->
<div>
<div>
个人资料:
<ul>
{#if $userInfo}
{#each Object.keys($userInfo) as key (key)}
<li>{key} : {$userInfo[key]}</li>
{/each}
{/if}
</ul>
</div>
<button on:click={handleSetInfo}>设置用户资料</button>
<button on:click={handleUpdateInfo}>更新</button>
</div>
16 slot
- Vue
Widget子组件
<script setup>
const props = defineProps({
goodsList: {
type: Array,
},
})
</script>
<template>
<header>
<slot name="header"> 标题 </slot>
<div><slot name="description"> 描述 </slot></div>
</header>
<main>
<ul>
<li v-for="(goods, key) in props?.goodsList" :key="key">
<slot name="default" :g="goods" :key="key">{{ goods }}</slot>
</li>
</ul>
</main>
<footer>
<slot name="footer"> 浏览量:100 </slot>
</footer>
</template>
<style scoped>
footer {
font-size: 12px;
}
</style>
SlotComponent父组件
<script setup>
import Widget from './Widget.vue'
import { ref } from 'vue'
const items = ref(['🍎', '🍌', '🍐'])
</script>
<template>
<Widget :goods-list="items">
<template #header> <h1>水果店</h1> </template>
<template #description>想吃新鲜水果的快点来呀</template>
<template #default="slotProps">
<span>下标 {{ slotProps.key }}</span>
<span>名称 {{ slotProps.g }}</span>
</template>
</Widget>
</template>
- Svelte
Widget子组件
<script>
export let items
</script>
<div>
<slot name="header">its header default text</slot>
<slot>its content default text</slot>
<!-- $$slots获取父级传递过来的参数 -->
{#if $$slots.description}
<slot name="description" />
{/if}
<!-- goods -->
<ul>
{#each items as item (item)}
<slot name='adb' {item} />
{/each}
</ul>
<slot name="footer">its footer default text</slot>
</div>
SlotWidget父组件
<script>
import SlotWidget from './SlotWidget.svelte'
let items = ['🍎', '🍌', '🍐']
</script>
<SlotWidget {items} let:item>
<div slot="header">世界你好</div>
<div slot="description">我是描述文本</div>
<div slot="default">名称{item}</div>
<svelte:fragment slot="footer">
<p>All rights reserved.</p>
<p>Copyright (c) 2019 Svelte Industries</p>
</svelte:fragment>
</SlotWidget>
17 声明周期
-
Vue
beforeCreate:在实例初始化之后,数据观测(data observer)和事件/监听事件配置之前被调用。created:实例创建完成后调用,此阶段完成了数据观测,属性和方法的运算,以及事件监听,$el属性还没有显示出来。beforeMount:在挂载开始之前被调用,相关的render函数首次被调用。这个时候还没有开始挂载节点,$el属性目标不会有任何变化。mounted:el被新创建的vm.��替换,并挂载到实例上去之后调用该钩子。如果实例被挂载到一个文档内元素上,当�������被调用时��.e**l替换,并挂载到实例上去之后调用该钩子。如果实例被挂载到一个文档内元素上,当mounted被调用时v**m.el也在文档内。beforeUpdate:数据更新时调用,发生在虚拟DOM打补丁之前。updated:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。destroyed:Vue实例销毁后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。
-
Svelte
beforeUpdate:Schedules a callback to run immediately before the component is updated after any state changeonMount: TheonMountfunction schedules a callback to run as soon as the component has been mounted to the DOM.afterUpdate:Schedules a callback to run immediately after the component has been updatedonDestroy:Schedules a callback to run immediately before the component is unmounted.