Английский оригинал:learn-vuejs
Китайский перевод:yoyoys
Эта страница представляет собой набор полезных шаблонов реализации Vue, методов, советов и полезных справочных ссылок.
- Vue Home Mode (Learn-Vuejs) Китайская версия
Объявление компонента
Однофайловый компонент (SFC) — наиболее распространенный
<template>
<button class="btn-primary" @click.prevent="handleClick">
{{text}}
</button>
</template>
<script>
export default {
data() {
return {
text: 'Click me',
};
},
methods: {
handleClick() {
console.log('clicked');
},
},
}
</script>
<style scoped>
.btn-primary {
background-color: blue;
}
</style>
Строковый шаблон (или литерал шаблона es6)
Vue.component('my-btn', {
template: `
<button class="btn-primary" @click.prevent="handleClick">
{{text}}
</button>
`,
data() {
return {
text: 'Click me',
};
},
methods: {
handleClick() {
console.log('clicked');
},
},
});
Функция рендеринга
Vue.component('my-btn', {
data() {
return {
text: 'Click me',
};
},
methods: {
handleClick() {
console.log('clicked');
},
},
render(h) {
return h('button', {
attrs: {
class: 'btn-primary'
},
on: {
click: this.handleClick,
},
});
},
});
JSX
Vue.component('my-btn', {
data() {
return {
text: 'Click me',
};
},
methods: {
handleClick() {
console.log('clicked');
},
},
render() {
return (
<button class="btn-primary" onClick={this.handleClick}>
{{this.text}}
</button>
);
},
});
vue-class-component(с использованием классов es6)
<template>
<button class="btn-primary" @click.prevent="handleClick">
{{text}}
</button>
</template>
<script>
import Vue from 'vue';
import Component from 'vue-class-component';
@Component
export default MyBtn extends Vue {
text = 'Click me';
handleClick() {
console.log('clicked');
}
}
</script>
<style scoped>
.btn-primary {
background-color: blue;
}
</style>
справочная ссылка
Условный рендеринг компонентов
Директивы (v-if / v-else / v-else-if / v-show)
v-if
<h1 v-if="true">只在 v-if 值為 true 時渲染</h1>
v-ifа такжеv-else
<h1 v-if="true">只在 v-if 值為 true 時渲染</h1>
<h1 v-else>只在 v-if 值為 false 時渲染</h1>
v-else-if
<div v-if="type === 'A'">只在 `type` 等於 `A` 時渲染</div>
<div v-else-if="type === 'B'">只在 `type` 等於 `B` 時渲染</div>
<div v-else-if="type === 'C'">只在 `type` 等於 `C` 時渲染</div>
<div v-else>只在 `type` 不等於>fmf `A` 或 `B` 或 `C` 時渲染</div>
v-show
<h1 v-show="true">永遠都會渲染,但是只在 `v-show` 值為 true 時顯示</h1>
Если вам нужно выполнить условный рендеринг для нескольких элементов одновременно, вы можете<template>используйте эти директивы для элементов (v-if / v-else / v-else-if /v-show). Уведомление:<template>Элементы на самом деле не оказывают домо.
<template v-if="true">
<h1>所有元素</h1>
<p>都會被渲染成為 DOM</p>
<p>除了 `template` 元素</p>
</template>
JSX
Если вы используете JSX Vue в своем приложении, вы можете использовать все операторы javascript, например,if else,switch case, тернарная операция (ternary) и логические операторы
if elseутверждение
export default {
data() {
return {
isTruthy: true,
};
},
render(h) {
if (this.isTruthy) {
return <h1>值為真時渲染</h1>;
} else {
return <h1>值為假時渲染</h1>;
}
},
};
switch caseутверждение
import Info from './Info';
import Warning from './Warning';
import Error from './Error';
import Success from './Success';
export default {
data() {
return {
type: 'error',
};
},
render(h) {
switch (this.type) {
case 'info':
return <Info text={text} />;
case 'warning':
return <Warning text={text} />;
case 'error':
return <Error text={text} />;
default:
return <Success text={text} />;
},
}
};
Вы также можете упростить сопоставление объектовswitch case
import Info from './Info';
import Warning from './Warning';
import Error from './Error';
import Success from './Success';
const COMPONENT_MAP = {
info: Info,
warning: Warning,
error: Error,
success: Success,
};
export default {
data() {
return {
type: 'error',
};
},
render(h) {
const Comp = COMPONENT_MAP[this.type || 'success'];
return <Comp />;
},
};
тернарный оператор
export default {
data() {
return {
isTruthy: true,
};
},
render(h) {
return (
<div>
{this.isTruthy ? (
<h1>值為真時渲染</h1>
) : (
<h1>值為假時渲染</h1>
)}
</div>
);
},
};
логический оператор
export default {
data() {
return {
isLoading: true,
};
},
render(h) {
return <div>{this.isLoading && <h1>Loading ...</h1>}</div>;
},
};
справочная ссылка
динамический элемент
использоватьisсобственность в<component>элемент
<component :is="currentTabComponent"></component>
Пример выше, оригинал<component>Элементы в , будут уничтожены одновременно с элементами переключения. Если вам нужно переключить и сохранить его<component>Сущность элемента посередине, не разрушаясь, может обернуть<keep-alive>маркировка следующим образом:
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
Комбинация компонентов
Базовый состав
<template>
<div class="component-b">
<component-a></component-a>
</div>
</template>
<script>
import ComponentA from './ComponentA';
export default {
components: {
ComponentA,
},
};
</script>
Расширяет
Может использоваться, когда вам нужно расширить компонент с одним файлом (SFC).
<template>
<button class="button-primary" @click.prevent="handleClick">
{{buttonText}}
</button>
</template>
<script>
import BaseButton from './BaseButton';
export default {
extends: BaseButton,
props: ['buttonText'],
};
</script>
справочная ссылка
Миксины
// closableMixin.js
export default {
props: {
isOpen: {
default: true
}
},
data: function() {
return {
shown: this.isOpen
}
},
methods: {
hide: function() {
this.shown = false;
},
show: function() {
this.shown = true;
},
toggle: function() {
this.shown = !this.shown;
}
}
}
<template>
<div v-if="shown" class="alert alert-success" :class="'alert-' + type" role="alert">
{{text}}
<i class="pull-right glyphicon glyphicon-remove" @click="hide"></i>
</div>
</template>
<script>
import closableMixin from './mixins/closableMixin';
export deafult {
mixins: [closableMixin],
props: ['text']
};
</script>
справочная ссылка
Слоты (по умолчанию)
<template>
<button class="btn btn-primary">
<slot></slot>
</button>
</template>
<script>
export default {
name: 'VBtn',
};
</script>
<template>
<v-btn>
<span class="fa fa-user"></span>
Login
</v-btn>
</template>
<script>
import VBtn from './VBtn';
export default {
components: {
VBtn,
}
};
</script>
справочная ссылка
Именованные слоты
BaseLayout.vue
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
App.vue
<base-layout>
<template slot="header">
<h1>這裡是頁面標題</h1>
</template>
<p>一段文件主體內的文字</p>
<p>另外一段文字</p>
<template slot="footer">
<p>一些聯絡資訊</p>
</template>
</base-layout>
Слоты с ограниченной областью действия
<template>
<ul>
<li
v-for="todo in todos"
v-bind:key="todo.id"
>
<!-- 保留一個插槽供每一個 todo 使用,-->
<!-- 並將 將 `todo` 物件作為插槽參數傳遞給它,供外部元件使用。-->
<slot v-bind:todo="todo">
{{ todo.text }}
</slot>
</li>
</ul>
</template>
<script>
export default {
name: 'TodoList',
props: {
todos: {
type: Array,
default: () => ([]),
}
},
};
</script>
<template>
<todo-list v-bind:todos="todos">
<template slot-scope="{ todo }">
<span v-if="todo.isComplete">✓</span>
{{ todo.text }}
</template>
</todo-list>
</template>
<script>
import TodoList from './TodoList';
export default {
components: {
TodoList,
},
data() {
return {
todos: [
{ todo: 'todo 1', isComplete: true },
{ todo: 'todo 2', isComplete: false },
{ todo: 'todo 3', isComplete: false },
{ todo: 'todo 4', isComplete: true },
];
};
},
};
</script>
использованная литература
- Getting Your Head Around Vue.js Scoped Slots
- Understanding scoped slots in Vue.js
- Scoped Component Slots in Vue.js
- The Trick to Understanding Scoped Slots in Vue.js
- The Power of Scoped Slots in Vue
Рендер реквизит
В большинстве случаев вы можете использовать Scoped Slots вместо Render Props, однако бывают ситуации, когда Render Props может быть полезен.
Для однофайловых компонентов:
<template>
<div id="app">
<Mouse :render="__render"/>
</div>
</template>
<script>
import Mouse from "./Mouse.js";
export default {
name: "app",
components: {
Mouse
},
methods: {
__render({ x, y }) {
return (
<h1>
The mouse position is ({x}, {y})
</h1>
);
}
}
};
</script>
<style>
* {
margin: 0;
height: 100%;
width: 100%;
}
</style>
ВJSX
const Mouse = {
name: "Mouse",
props: {
render: {
type: Function,
required: true
}
},
data() {
return {
x: 0,
y: 0
};
},
methods: {
handleMouseMove(event) {
this.x = event.clientX;
this.y = event.clientY;
}
},
render(h) {
return (
<div style={{ height: "100%" }} onMousemove={this.handleMouseMove}>
{this.$props.render(this)}
</div>
);
}
};
export default Mouse;
справочная ссылка
Передача реквизита
Иногда вы хотите передать все параметры (реквизиты) и события (слушатели) дочернему элементу, но не хотите объявлять все параметры дочернего элемента. вы можете напрямую$attrsа также$listenersПривязать к дочернему элементу.
<template>
<div>
<h1>{{title}}</h1>
<child-component v-bind="$attrs" v-on="$listeners"></child-component>
</div>
</template>
<script>
export default {
name: 'PassingPropsSample'
props: {
title: {
type: String,
default: 'Hello, Vue!'
}
}
};
</script>
В родительском элементе вы можете сделать это:
<template>
<passing-props-sample
title="Hello, Passing Props"
childPropA="This props will properly mapped to <child-component />"
@click="handleChildComponentClick"
>
</passing-props-sample>
</template>
<script>
import PassingPropsSample from './PassingPropsSample';
export default {
components: {
PassingPropsSample
},
methods: {
handleChildComponentClick() {
console.log('child component clicked');
}
}
};
</script>
использованная литература
Компонент высшего порядка (HOC)
справочная ссылка
- Higher Order Components in Vue.js
- Do we need Higher Order Components in Vue.js?
- Higher-Order Components in Vue.js
Внедрение зависимости
Поддержка Vueпоставкаа такжеинъекция(Предоставить/внедрить) механизм для передачи объекта всем дочерним компонентам, независимо от того, насколько глубока структура, если они основаны на одном и том же родительском компоненте. Уведомление:provideа такжеinjectНет реактивной способности, если только объект, который вы передаете, не является реактивным по своей природе.
<parent-component> // 父元件
<child-component> // 子元件
<grand-child-component></grand-child-component> // 孫元件
</child-component>
</ancestor-component>
Вышеупомянутая структура компонентов, если вы хотите от父元件Для получения данных необходимо передать параметр (props) передать данные子元件а также孫元件среди. но если父元件 поставка (provide) данные (или объекты),孫元件непосредственно, объявивинъекция (inject)
父元件Данные (или объекты), определенные в .
справочная ссылка
- Official API
- Official Guide
- Component Communication
- Dependency Injection in Vue.js App with TypeScript
поставкаа такжеинъекция (Provide / Inject)
// ParentComponent.vue
export default {
provide: {
theme: {
primaryColor: 'blue',
},
},
};
// GrandChildComponent.vue
<template>
<button :style="{ backgroundColor: primary && theme.primaryColor }">
<slot></slot>
</button>
</template>
<script>
export default {
inject: ['theme'],
props: {
primary: {
type: Boolean,
default: true,
},
},
};
</script>
Внедрить шаблон декоратора (@Provide / @Inject Decorator)
// ParentComponent.vue
import { Component, Vue, Provide } from 'vue-property-decorator';
@Component
export class ParentComponent extends Vue {
@Provide
theme = {
primaryColor: 'blue',
};
}
// GrandChildComponent.vue
<template>
<button :style="{ backgroundColor: primary && theme.primaryColor }">
<slot></slot>
</button>
</template>
<script>
import { Component, Vue, Inject, Prop } from 'vue-property-decorator';
export class GrandChildComponent extends Vue {
@Inject() theme;
@Prop({ default: true })
primary: boolean;
};
</script>
Обработка ошибок
errorCapturedмероприятие
export default {
name: 'ErrorBoundary',
data() {
return {
error: false,
errorMessage: '',
};
},
errorCaptured (err, vm, info) {
this.error = true;
this.errorMessage = `${err.stack}\n\nfound in ${info} of component`;
return false;
},
render (h) {
if (this.error) {
return h('pre', { style: { color: 'red' }}, this.errorMessage);
}
return this.$slots.default[0]
}
};
<error-boundary>
<another-component/>
</error-boundary>
скопировать код
пример
справочная ссылка
Советы по продуктивности
Сделать слушателя активным в созданном событии
// 不要這樣做
created() {
this.fetchUserList();
},
watch: {
searchText: 'fetchUserList',
}
// 這樣做
watch: {
searchText: {
handler: 'fetchUserList',
immediate: true,
}
}
Полезные ссылки
общение между группами
- Vue.js Event Bus + Promises
- Vue.js Component Communication Patterns
- Leveraging Vue events to reduce prop declarations
- Control DOM Outside Your Vue.js App with portal-vue
- Creating Custom Inputs With Vue.js
- Creating a Global Event Bus with Vue.js
Советы по рефакторингу
- Refactoring Vue: Cleaning Up a List of Posts With Better Component Splitting and More ES6
- Clean up your Vue modules with ES6 Arrow Functions
- Примеры чистого кода Vue
- Optimizing Performance with Computed Properties
Vuex
- Decouple Vuex modules with the Mediator pattern
- Геттеры Vuex великолепны, но не злоупотребляйте ими
- Reusable Vuex Mutation Functions
- A pattern to handle ajax requests in Vuex
- [vuex Mutations] Single Changes vs. Single Responsibility
- Components and How They Interact in Vue and Vuex
- Why VueX Is The Perfect Interface Between Frontend and API
- Composing actions with Vuex
- How to Build Complex, Large-Scale Vue.js Apps With Vuex
Mobx
Компонент без рендеринга
пример
Структура каталогов
Советы
- Как создавать компоненты Vue как профессионал 😎
- Four tips for working with Vue.js
- Tips from a Lowly VueJS Developer
- Throttling and Debouncing Events with Vue.js and lodash
- Are partially applied functions in event handlers possible?
- Vue.js — Соображения и хитрости
- Six random issues and their solutions in VueJS.
- When VueJS Can't Help You
Пример проекта
Плохая демонстрация (анти-шаблон)
- Chris Fritz - Vue.js Anti-Patterns (and How to Avoid Them)
- Common mistakes to avoid while working with Vue.js
Видео и аудио уроки
- 81: Evan You - Advanced Vue Component Design
- 7 секретных шаблонов, о которых консультанты Vue не хотят, чтобы вы знали
Платные курсы
Дополнительная информация
- Creating an Interpose Vue component from a React implementation
- Composing computed properties in Vue.js
- 4 AJAX Patterns For Vue.js Apps
- 3 Code Splitting Patterns For VueJS and Webpack
- The easiest way to improve your Vue.js application. Part 1
- Using JSX with Vue and Why You Should Care
- Compound components
- Creating Multi-root Vue.js Components
- Understanding Vue.js Reactivity in Depth with Object.defineProperty()
- Templating in Vue: Separation of Concerns or Separation of Technology or something else?
- Stashing Vue components data
- Creating Reusable Transitions in Vue
- vue-advanced-workshop
- Do it with Elegance: How to Create Data-Driven User Interfaces in Vue
- Creating Vue.js Component Instances Programmatically
- Managing User Permissions in a Vue.js App
- Render Functional Components in Vue.js
- Templating in Vue: Separation of Concerns or Separation of Technology or something else?
- Looping through Object Properties
- Cancelling async operations in Vue.js
- Scoped styles with v-html
- Pagination With Vuejs
- Что означает буква «h» в методе рендеринга Vue?
- How To Build Vue Components That Play Nice
- Making responsive Vue components with ResizeObserver
- An imperative guide to forms in Vue.js
- Vue.js: the good, the meh, and the ugly