Vue
Vue
Sharing State
原代码/src/App.vue
<template>
<div>
Search for <input v-model="searchInput" />
<div>
<p>Loading: {{ loading }}</p>
<p>Error: {{ error }}</p>
<p>Number of events: {{ results }}</p>
</div>
</div>
</template>
<script>
import { ref, watch } from "@vue/composition-api";
import eventApi from "@/api/event.js";
export default {
setup() {
const searchInput = ref("");
const results = ref(null);
const loading = ref(false);
const error = ref(null);
async function loadData(search) {
loading.value = true;
error.value = null;
results.value = null;
try {
results.value = await eventApi.getEventCount(search.value);
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
}
watch(searchInput, () => {
if (searchInput.value !== "") {
loadData(searchInput);
} else {
results.value = null;
}
});
return { searchInput, results, loading, error };
}
};
</script>
调整后
/composables/use-promise.js
import { ref } from "@vue/composition-api";
export default function usePromise(fn) { // fn is the actual API call
const results = ref(null);
const loading = ref(false);
const error = ref(null);
const createPromise = async (...args) => { // Args is where we send in searchInput
loading.value = true;
error.value = null;
results.value = null;
try {
results.value = await fn(...args); // Passing through the SearchInput
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
};
return { results, loading, error, createPromise };
}
/src/App.vue
<template>
<div>
Search for <input v-model="searchInput" />
<div>
<p>Loading: {{ getEvents.loading }}</p>
<p>Error: {{ getEvents.error }}</p>
<p>Number of events: {{ getEvents.results }}</p>
</div>
</div>
</template>
<script>
import { ref, watch } from "@vue/composition-api";
import eventApi from "@/api/event.js";
import usePromise from "@/composables/use-promise";
export default {
setup() {
const searchInput = ref("");
const getEvents = usePromise(search =>
eventApi.getEventCount(search.value)
);
watch(searchInput, () => {
if (searchInput.value !== "") {
getEvents.createPromise(searchInput);
} else {
getEvents.results.value = null;
}
});
return { searchInput, getEvents };
}
};
</script>
Suspense
<template>
<Suspense>
<template #default>
<!-- Put component/components here, one or more of which makes an asychronous call -->
</template>
<template #fallback>
<!-- What to display when loading -->
</template>
</Suspense>
</template>
<template>
<Suspense>
<template #default>
<Event />
</template>
<template #fallback>
Loading...
</template>
</Suspense>
</template>
<script>
import Event from "@/components/Event.vue";
export default {
components: { Event },
};
</script>
<template>
...
</template>
<script>
import useEventSpace from "@/composables/use-event-space";
export default {
async setup() {
const { capacity, attending, spacesLeft, increaseCapacity } = await useEventSpace();
return { capacity, attending, spacesLeft, increaseCapacity };
},
};
</script>
useAsyncQueue
https://www.vuemastery.com/blog/coding-better-composables-5-of-5/#useasyncqueue
参数绑定
v-bind with No Argument
原
<template>
<img v-bind:src="imageAttrs.src" v-bind:alt="imageAttrs.text" />
</template>
<script>
export default {
data() {
return {
imageAttrs: {
src: '/vue-mastery-logo.png',
text: 'Vue Mastery Logo'
}
}
}
}
</script>
改一
<img v-bind="{ src: imageAttrs.src, alt: imageAttrs.text }" />
改二
<img v-bind="imageAttrs" />
v-on with No Arguments
原
<template>
<img v-on:click="openGallery" v-on:mouseover="showTooltip" />
</template>
<script>
export default {
methods: {
openGallery() { ... },
showTooltip() { ... }
}
}
</script>
改一
<template>
<img v-on="{ click: openGallery, mouseover: showTooltip }" />
</template>
改二
<script>
export default {
computed: {
inputEvents: {
click: this.openGallery,
mouseover: this.showTooltip
}
},
methods: {
openGallery() { ... },
showTooltip() { ... }
}
}
</script>
复杂参数
<template>
<main>
<Component
v-for="content in apiResponse"
:key="content.id"
:is="content.type"
:article-title="content.title"
:article-content="content.body"
:ad-image="content.image"
:ad-heading="content.heading"
@click="content.type === 'NewsArticle' ? openArticle : openAd"
@mouseover="content.type === 'NewsArticle' ? showPreview : trackAdEvent"
/>
</main>
</template>
改
<template>
<main>
<Component
v-for="content in apiResponse"
:key="content.id"
:is="content.type"
v-bind="feedItem(content).attrs"
v-on="feedItem(content).events"
/>
</main>
</template>
<script>
export default {
methods: {
feedItem(item) {
if (item.type === 'NewsArticle') {
return {
attrs: {
'article-title': item.title,
'article-content': item.content
},
events: {
click: this.openArticle,
mouseover: this.showPreview
}
}
} else if (item.type === 'NewsAd') {
return {
attrs: {
'ad-image': item.image,
'ad-heading': item.heading
},
events: {
click: this.openAd,
mouseover: this.trackAdEvent
}
}
}
}
}
}
</script>