theme | title | lineNumbers | transition |
---|---|---|---|
apple-basic |
Vue.js - Nutzung, Unterschiede und sein Ecosystem |
true |
fade-out |
Nutzung, Eigenheiten und sein Ökosystem
<style> .slidev-layout { --uno: h-full flex flex-col justify-center } h1 { --uno: text-6xl font-700 leading-20 } h1 + p { --uno: font-700 -mt-4 text-2xl; } </style><script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button class="button" @click="count++">Count is: {{ count }}</button>
</template>
<style scoped>
.button {
background-color: grey;
padding: 0.25rem 1rem;
border-radius: 0.25rem;
}
</style>
"Go with Options API if you are not using build tools, or plan to use Vue primarily in low-complexity scenarios, e.g. progressive enhancement."
"Go with Composition API + Single-File Components if you plan to build full applications with Vue."
```vue
<script>
</script>
<template>
</template>
<style>
</style>
```
```vue
<script>
</script>
<template>
</template>
<style>
</style>
<i18n>
</i18n>
```
```vue
<script>
</script>
<template>
</template>
<style lang="scss">
</style>
<i18n>
</i18n>
```
```vue
<script setup>
const { t } = useI18n({ ... })
</script>
<template>
<p>{{ t('hello') }}</p>
</template>
<style lang="scss">
</style>
<i18n lang="json">
{
"en": {
"hello": "Hello world!"
},
"de": {
"hello": "Hallo Welt!"
}
}
</i18n>
```
```html {all|5|15|17-22|8-12}
<!doctype html>
<html>
<head>
<title>Vue ohne Build Tool</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<button @click="count++">
Count is: {{ count }}
</button>
</div>
</body>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const count = ref(0)
return { count }
}
}).mount('#app')
</script>
</html>
```
```html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Vue ohne Build Tool</title>
<script src="https://unpkg.com/petite-vue" defer init></script>
</head>
<body>
<div v-scope="{ count: 0 }">
<button @click="count++">
Count is: {{ count }}
</button>
</div>
</body>
</html>
```
ref()
```vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
```
```vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
</script>
```
```vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
</script>
```
```vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
</script>
<template>
<!-- Automatisch Unrefed -->
<div>{{ count }}</div>
</template>
```
```vue
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
return { count }
}
}
</script>
<template>
<!-- Automatisch Unrefed -->
<div>{{ count }}</div>
</template>
```
reactive()
const state = reactive({ count: 0 })
console.log(state.count) // 0
state.count++
console.log(state.count) // 1
Limitationen
```js
const state = reactive({ count: 0 })
state = { count: 1 }
console.log(state.count) // 0
let { count } = state
count++
console.log(state.count) // 0
// reactivity verloren
callSomeFunction(state.count)
```
```js
const state = ref({ count: 0 })
state.value = { count: 1 }
console.log(state.value.count) // 1
let { count } = toRefs(state.value)
count.value++
console.log(state.value.count) // 2
// reactivity bleibt
callSomeFunction(state.value.count)
```
```js
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed(() => {
return firstName.value + ' ' + lastName.value
})
```
```js
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
get() {
return firstName.value + ' ' + lastName.value
},
// Nicht empfohlen
set(newValue) {
names = newValue.split(' ')
firstName.value = names[0]
lastName.value = names[1]
}
})
```
<!-- Data binding "Mustache" syntax -->
<span>Count is: {{ count }}</span>
```vue-html
<!-- Attribut binding -->
<div v-bind:id="id"></div>
```
```vue-html
<!-- Shorthand Attribut binding -->
<div :id="id"></div>
```
```vue-html
<!-- Shorthand Attribut binding (ab v3.4) -->
<div :id></div>
```
<!-- Multiple Attribut binding -->
<script setup>
const objectOfAttrs = {
id: 'container',
class: 'wrapper',
style: 'background-color:green'
}
</script>
<template>
<div v-bind="objectOfAttrs"></div>
</template>
<!-- JavaScript Expressions -->
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<button :disabled="age < 18">Registrieren</button>
<!-- Conditional rendering -->
<p v-if="age < 13">Du bist noch ein Kind</p>
<p v-else-if="age < 18">Du bist ein Teenager</p>
<p v-else>Du bist erwachsen</p>
<!-- Conditional visibility -->
<p v-show="seen">Ich werde angezeigt wenn 'seen' truthy ist</p>
```vue
<!-- Lists -->
<div v-for="item in items">
{{ item.text }}
</div>
```
```vue
<!-- Lists -->
<div v-for="item in items" :key="item.id">
{{ item.text }}
</div>
```
<!-- List Range -->
<span v-for="n in 10">{{ n }}</span>
```vue
<!-- Events -->
<button v-on:[eventName]="count++"> ... </button>
```
```vue
<!-- Events -->
<button v-on:click="count++"> ... </button>
```
```vue
<!-- Events Shorthand -->
<button @click="count++"> ... </button>
```
<!-- Events Method Handler -->
<button @click="onButtonClick"> ... </button>
<!-- Modifier -->
<form @submit.prevent="submit"> ... </form>
<!-- Key Modifier -->
<input @keyup.enter="submit" />
<!-- Andere Integrierte Directives -->
v-text, v-html, v-model, v-slot, v-pre, v-once, v-memo, v-cloak
<!-- Andere Integrierte Modifier -->
.stop, .prevent, .self, .capture, .once, .passive, ...
<!-- Andere Integrierte Key Modifier -->
.enter, .tab, .delete, .esc, .space, .up, .down, .left, .right, ...
```vue
<template>
<input :value="text" @input="event => text = event.target.value">
<input type="checkbox" :checked="accepted" @change="_ => accepted = !accepted">
<input type="radio" :checked="accepted" @change="_ => accepted = !accepted">
<select :value="selected" @change="event => selected = event.target.value">
<option>A</option>
<option>B</option>
<option>C</option>
</selected>
</template>
```
```vue
<template>
<input v-model="text">
<input type="checkbox" v-model="accepted">
<input type="radio" v-model="accepted">
<select v-model="selected">
<option>A</option>
<option>B</option>
<option>C</option>
</selected>
</template>
```
<script setup>
const checkedNames = ref([])
</script>
<template>
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
</template>
```vue-html
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no" />
```
```vue-html
<input
type="checkbox"
v-model="toggle"
:true-value="dynamicTrueValue"
:false-value="dynamicFalseValue" />
```
```vue
<script setup>
const selected = ref("A")
</script>
<template>
<div>Selected: {{ selected }}</div>
<select v-model="selected">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</template>
```
```vue
<script setup>
const selected = ref([])
</script>
<template>
<div>Selected: {{ selected }}</div>
<select multiple v-model="selected">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</template>
```
```vue
<script setup>
const selected = ref([])
</script>
<template>
<div>Selected: {{ selected }}</div>
<select multiple v-model="selected">
<option :value="{ code: 'A' }">A</option>
<option :value="{ code: 'B' }">B</option>
<option :value="{ code: 'C' }">C</option>
</select>
</template>
```
<!-- Nutzt @change anstatt von @input -->
<input v-model.lazy="msg" />
<!-- Casted mit parseFloat -->
<input v-model.number="age" />
<!-- Entfernt whitespace -->
<input v-model.trim="msg" />
```vue
<script setup>
const question = ref('')
const answer = ref('')
const loading = ref(false)
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.includes('?')) {
loading.value = true
answer.value = 'Thinking...'
try {
answer.value = (await (await fetch('https://yesno.wtf/api')).json()).answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
} finally {
loading.value = false
}
}
})
</script>
<template>
<p>Stelle eine Ja oder Nein Frage: <input v-model="question" :disabled="loading" /></p>
<p>{{ answer }}</p>
</template>
```
```vue
<script setup>
const question = ref('')
const answer = ref('')
const loading = ref(false)
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.includes('?')) {
loading.value = true
answer.value = 'Thinking...'
try {
answer.value = await (await fetch('https://yesno.wtf/api')).json().answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
} finally {
loading.value = false
}
}
})
</script>
```
```js
const itemId = ref(1)
const data = ref(null)
watch(
itemId,
async () => {
const response = await fetch(`https://server:port/items/${itemId.value}`)
data.value = await response.json()
}
)
```
```js
const itemId = ref(1)
const data = ref(null)
watch(
itemId,
async () => {
const response = await fetch(`https://server:port/items/${itemId.value}`)
data.value = await response.json()
},
{ immediate: true }
)
```
```js
const itemId = ref(1)
const data = ref(null)
watchEffect(async () => {
const response = await fetch(`https://server:port/items/${itemId.value}`)
data.value = await response.json()
})
```
```vue
<script setup>
const question = ref('')
const answer = ref('')
const loading = ref(false)
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.includes('?')) {
loading.value = true
answer.value = 'Thinking...'
try {
answer.value = await (await fetch('https://yesno.wtf/api')).json().answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
} finally {
loading.value = false
}
}
})
</script>
```
```js
// api.ts
export function useAskYesNoQuestion() {
const question = ref('')
const answer = ref('')
const loading = ref(false)
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.includes('?')) {
loading.value = true
answer.value = 'Thinking...'
try {
answer.value = await (await fetch('https://yesno.wtf/api')).json().answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
} finally {
loading.value = false
}
}
})
return { question, answer, loading }
}
```
```vue
<script setup>
import { useAskYesNoQuestion } from './api.ts'
const { question, answer, loading } = useAskYesNoQuestion()
</script>
```
```vue
<!-- ButtonCounter.vue -->
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">Count is: {{ count }}</button>
</template>
```
```vue
<!-- ButtonCounter.vue -->
<script setup lang="ts">
import { ref, defineProps } from 'vue'
const count = ref(0)
const props = defineProps<{ steps: number }>()
</script>
<template>
<button @click="count++">Count is: {{ count * props.steps }}</button>
</template>
```
```vue
<!-- ButtonCounter.vue -->
<script setup lang="ts">
import { ref, defineProps, withDefaults } from 'vue'
const count = ref(0)
const props = withDefaults(defineProps<{ steps: number }>(), {
steps: 1
})
</script>
<template>
<button @click="count++">Count is: {{ count * props.steps }}</button>
</template>
```
```vue
<!-- ButtonCounter.vue -->
<script setup lang="ts">
import { ref, defineProps } from 'vue'
const count = ref(0)
// Ab v3.5 mit Reactive Props Destructure
const { steps = 1 } = defineProps<{ steps: number }>()
</script>
<template>
<button @click="count++">Count is: {{ count * steps }}</button>
</template>
```
```vue
<!-- ButtonCounter.vue -->
<script setup lang="ts">
import { ref, defineProps } from 'vue'
const count = ref(0)
const { steps = 1 } = defineProps<{ steps: number }>()
const emit = defineEmits<{
(e: 'reset'): void
}>()
</script>
<template>
<button @click="count++">Count is: {{ count * steps }}</button>
<button @click="emit("reset")" />
</template>
```
```vue
<!-- ButtonCounter.vue -->
<script setup lang="ts">
import { ref, defineProps } from 'vue'
const count = ref(0)
const { steps = 1 } = defineProps<{ steps: number }>()
const emit = defineEmits<{
(e: 'reset', newCount: number): void
}>()
</script>
<template>
<button @click="count++">Count is: {{ count * steps }}</button>
<button @click="emit("reset", 10)" />
</template>
```
```vue
<!-- ButtonCounter.vue -->
<script setup lang="ts">
import { ref, defineProps } from 'vue'
const count = ref(0)
const { steps = 1 } = defineProps<{ steps: number }>()
const emit = defineEmits<{
reset: [newCount: number] // Ab v3.3
}>()
</script>
<template>
<button @click="count++">Count is: {{ count * steps }}</button>
<button @click="emit("reset", 10)" />
</template>
```
```vue
<!-- ButtonCounter.vue -->
<script setup lang="ts">
import { ref, defineProps } from 'vue'
const count = ref(0)
const { steps = 1 } = defineProps<{ steps: number }>()
const emit = defineEmits<{
reset: [newCount: number]
}>()
</script>
<template>
<button v-bind="$attrs" @click="count++">Count is: {{ count * steps }}</button>
<button @click="emit("reset", 10)" />
</template>
```
```vue
<!-- OtherComponent.vue -->
<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script>
<template>
<ButtonCounter />
</template>
```
```vue
<!-- OtherComponent.vue -->
<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script>
<template>
<ButtonCounter class="red-button" />
</template>
```
```vue
<!-- Card.vue -->
<script setup lang="ts">
const props = defineProps<{ title: string, body: string }>()
</script>
<template>
<div>
<h3>{{ props.title }}</h3>
<p>{{ props.body }}</p>
</div>
</template>
```
```vue
<!-- Card.vue -->
<script setup lang="ts">
const props = defineProps<{ title: string }>()
</script>
<template>
<div>
<h3>{{ props.title }}</h3>
<slot />
</div>
</template>
```
```vue
<!-- Card.vue -->
<script setup lang="ts">
</script>
<template>
<div>
<slot name="title" />
<slot>Keine Informationen</slot>
</div>
</template>
```
```vue
<script setup>
import Card from './Card.vue'
</script>
<template>
<Card
title="Vue.js"
body="An approachable, performant and versatile framework for building web user interfaces."
/>
</template>
```
```vue
<script setup>
import Card from './Card.vue'
</script>
<template>
<Card title="Vue.js">
An approachable, performant and versatile framework for building web user interfaces.
</Card>
</template>
```
```vue
<script setup>
import Card from './Card.vue'
</script>
<template>
<Card title="Vue.js">
<template v-slot:title>
<h2>Vue.js</h2>
</template>
An approachable, performant and versatile framework for building web user interfaces.
</Card>
</template>
```
```vue
<script setup>
import Card from './Card.vue'
</script>
<template>
<Card title="Vue.js">
<template #title>
<h2>Vue.js</h2>
</template>
An approachable, performant and versatile framework for building web user interfaces.
</Card>
</template>
```
```vue
<template>
<div class="card">
<div class="card-header">
<slot name="title" />
</div>
<slot>Keine Informationen</slot>
</div>
</template>
```
```vue
<template>
<div class="card">
<div v-if="$slots.header" class="card-header">
<slot name="title" />
</div>
<slot>Keine Informationen</slot>
</div>
</template>
```
```vue
<!-- List.vue -->
<template>
<ul>
<li v-for="item in items">
<slot name="item" />
</li>
</ul>
</template>
```
```vue
<!-- List.vue -->
<template>
<ul>
<li v-for="item in items">
<slot name="item" :name="item.name" :rating="item.rating" />
</li>
</ul>
</template>
```
```vue
<!-- List.vue -->
<template>
<ul>
<li v-for="item in items">
<slot name="item" v-bind="item" />
</li>
</ul>
</template>
```
```vue
<!-- Main.vue -->
<template>
<List>
<template #item>
Das ist nicht so sinnvoll
</template>
</List>
</template>
```
```vue
<!-- Main.vue -->
<template>
<List>
<template #item="{ name, rating }">
{{ name }} - {{ rating }} Bewertung
</template>
</List>
</template>
```
```vue
<script setup>
import Home from './Home.vue'
import Posts from './Posts.vue'
import Archive from './Archive.vue'
import { ref } from 'vue'
const currentTab = ref('Home')
const tabs = ['Home', 'Posts', 'Archive']
</script>
<template>
<button
v-for="tab in tabs"
:key="tab"
@click="currentTab = tab"
>
{{ tab }}
</button>
<Home v-if="currentTab === 'Home'" />
<Posts v-if="currentTab === 'Posts'" />
<Archive v-if="currentTab === 'Archive'" />
</template>
```
```vue
<script setup>
// imports...
const currentTab = ref('Home')
const tabs = { Home, Posts, Archive }
</script>
<template>
<button
v-for="(_, tab) in tabs"
:key="tab"
@click="currentTab = tab"
>
{{ tab }}
</button>
<component :is="tabs[currentTab]" />
</template>
```
```vue
<style scoped>
.example {
color: red;
}
</style>
<template>
<div class="example">hi</div>
</template>
```
```vue
<style>
.example[data-v-f3f3eg9] {
color: red;
}
</style>
<template>
<div class="example" data-v-f3f3eg9>hi</div>
</template>
```
```vue
<style module>
.example {
color: red;
}
</style>
<template>
<div :class="$style.red">hi</div>
</template>
```
```vue
<style scoped>
div {
/* Wird eine CSS Variable */
color: v-bind('theme.color');
}
</style>
<template>
<div>hi</div>
</template>
<script setup>
import { ref } from 'vue'
const theme = ref({
color: 'red',
})
</script>
```
```vue
<template>
<div :class="(isActive ? 'active' : '') + (hasError ? ' text-danger' : '') + ' static'" />
</template>
```
```vue
<template>
<div
class="static"
:class="{ 'active': isActive, 'text-danger': hasError }" />
</template>
```
```vue
<template>
<div
class="static"
:class="[activeClasses, errorClasses]" />
</template>
```
```vue
<template>
<div
class="static"
:class="[{ [activeClasses]: isActive }, errorClasses]" />
</template>
```
- Vite - Build Tool
- Vitest - Testing Framework
- Nuxt - Metaframework für SSR, SSG, ESG, ISR oder Hybrid
- Vueuse - Composition Utilities
- Tanstack Query - Asynchronous state management
- radix-vue - Unstyled, accessible Components
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<div>
<button @click="count++">
{{ count }}
</button>
</div>
</template>
// Vereinfachter Code
const t0 = template("<div><button></button></div>")
delegateEvents("click")
export default {
...
setup(props, { expose }) {
expose();
const count = ref(0)
return { count, ref }
}
render(ctx) {
const div = t0()
const b = div.firstChild
delegate(b, "click", () => () => (ctx.count++))
renderEffect(() => setText(b, ctx.count))
return div
}
}
- KeepAlive
- Transition/-Group
- Teleport
- Suspense and Async Components
- Provide/Inject
- Template Refs
- Eigene Plugins oder Directives
- ...
Die Folien gibt es hier github.com/mello-r/vue-introduction