предисловие
Режим публикации-подписки также называется режимом наблюдателя. Он определяет отношения «один ко многим» между объектами, позволяя нескольким объектам-наблюдателям одновременно отслеживать определенный подчиненный объект. будут контролироваться будут уведомлены.
Это не конкретная реализация, а шаблон, разработанный компьютерным языком, чтобы привести живой пример.
Бомба с дистанционным управлением - это своеобразное приложение жизни "опубликуй и подпишись". Закапываете бомбу 💣 под определенной машиной, а потом садитесь в Старбакс напротив машины пить кофе. Как только добыча садится в машину, нажимаете кнопку и бомба взрывается. Во время всего этого процесса бомба "подписывается" на вас, а право "опубликовать" - это кнопка на вашей руке.
Интерфейсные приложения
Фактически, как разработчик интерфейса, вы уже использовали шаблон проектирования "публикация и подписка". Если вы мне не верите, посмотрите на следующий код:
document.body.addEventListener('click', () => {
console.log('监听点击事件')
})
Приведенный выше код проходитaddEventListener
метод подписанbody
событие щелчка, щелкните любойbody
Теги внутри вызовут выполнение функции обратного вызова. Это принцип делегирования событий,jQuery
Реализация в этом отношении также аналогична следующему:
$('.demo').on('click', () => {
// dosomethiong
})
Еще одно классическое применение модели «публикация и подписка» —Vue 2.x
Принцип двустороннего связывания вObject.defineProperty
, см. следующий код:
const obj = { name: 'Nick' }
Object.defineProperty(obj, 'name', {
set: function () {
console.log('触发更新')
}
})
подписался в кодеname
свойство, как только оно изменится,set
Функция будет выполнена. Также нам не нужно заботитьсяname
Когда атрибут изменится, пока он смеет меняться,set
будет запущен.
скажи еще одинVue
Модель «опубликовать и подписаться», о которой все часто пишут в разработке:
<Child @submit="sendPost"></Child>
Я верю, что это было написаноVue
Моим одноклассникам не чужды.Это способ передачи значений между компонентами, а подкомпоненты передаются понемногу.emit
Выпуск методаsubmit
, родительский компонентsendPost
метод будет запущен.
Таким образом, применение модели «публикация и подписка» во фронтенде достигло своего пика.
Написание простого EventBus от руки
Кратко опишу требования, класс EventBus бросает три метода, а именно:
- on: метод подписки, введите метод on в компоненте или на странице и определите метод запускаемой функции.
- emit: метод триггера, в соответствии с указанным выше методом подписки, активируйте его.
- off: тип подписки, которую нужно уничтожить, аналогично
document.removeEventListener
.
Скопируй парня, открой весь
class EventBus {
constructor() {
this.handleMaps = {} // 初始化一个存放订阅回调方法的执行栈
}
// 订阅方法,接收两个参数
// type: 类型名称
// handler:订阅待执行的方法
on(type, handler) {
if (!(handler instanceof Function)) {
throw new Error('别闹了,给函数类型') // handler 必须是可执行的函数
}
// 如果类型名不存在,则新建对应类型名的数组
if (!(type in this.handleMaps)) {
this.handleMaps[type] = []
}
// 将待执行方法塞入对应类型名数组
this.handleMaps[type].push(handler)
}
// 发布方法,接收两个参数
// type:类型名称
// params:传入待执行方法的参数
emit(type, params) {
if (type in this.handleMaps) {
this.handleMaps[type].forEach(handler => {
// 执行订阅时,塞入的待执行方法,并且带入 params 参数
handler(params)
})
}
}
// 销毁方法
off(type) {
if (type in this.handleMaps) {
delete this.handleMap[type]
}
}
}
export default new EventBus()
Просто напишите мини EventBus, основная идея такова.
применяется на практике
Уровень всегда должен быть проверен, чтобы увидеть, работает он или нет! !
Далее мы проходимVue CLI
Инициализируйте базовый проект и импортируйте код, написанный выше. как показано на рисунке:
новый
utils/event_bus.js
, в котором хранится написанный выше код.
Проверка 1: связь между родительским и дочерним компонентами
ИсправлятьHome.vue
Следующим образом:
<template>
<div class="home">
技能:{{ skill }}
<Child />
</div>
</template>
<script>
import Child from '@/components/Child'
import eventBus from '@/utils/event_bus'
import { onMounted, ref } from 'vue'
export default {
name: 'Home',
components: {
Child
},
setup() {
const skill = ref('')
onMounted(() => {
// 订阅 skill 类型名
eventBus.on('skill', (key) => {
skill.value = key
console.log('key', key)
})
})
return {
skill
}
}
}
</script>
Добавить кcomponents/Child.vue
,Следующим образом:
<template>
<div>
<button @click="play">释放子技能</button>
<Grandson />
</div>
</template>
<script>
import eventBus from '@/utils/event_bus'
export default {
name: 'Child',
setup() {
const play = () => {
// 发布 skill 类型方法,并且传参数
eventBus.emit('skill', '狮子歌歌')
}
return {
play
}
}
}
</script>
Давайте посмотрим на эффект отображения в браузере:Очевидно, что нажатие кнопки «Освобождение вспомогательного навыка» вызывает событие подписанного навыка.
Проверка 2: Связь между компонентами внука и внука
Добавляем еще один компонент-внукcomponents/Grandson.vue
, код показан ниже:
<template>
<div>
<button @click="play">释放孙技能</button>
</div>
</template>
<script>
import eventBus from '@/utils/event_bus'
export default {
name: 'Grandson',
setup() {
const play = () => {
eventBus.emit('skill_2', '三千烦恼')
}
return {
play
}
}
}
</script>
Child.vue
Добавьте в компонент следующий код:
<template>
...
<Grandson />
</template>
<script>
import Grandson from './Grandson'
export default {
name: 'Child',
components: {
Grandson
}
}
</script>
Давайте посмотрим на эффект отображения в браузере:
Проверка 3: Межкомпонентная коммуникация
Эту проблему должен решить EventBus, модифицируя исходный проектviews/About.vue
Код компонента выглядит следующим образом:
<template>
<div class="about">
<button @click="play">释放技能</button>
</div>
</template>
<script>
import eventBus from '@/utils/event_bus'
export default {
name: 'About',
setup() {
const play = () => {
eventBus.emit('skill', '跨组件的狮子歌歌')
}
return {
play
}
}
}
</script>
В браузере отображается следующее:
Суммировать
Плагины управления состоянием на рынке, будь то Vuex, Redux, Mobx и т. д., используют модель «публикация и подписка». Его дизайнерские идеи достойны нашего глубокого осмысления и исследования.Вышеприведенные рукописные предложенияEventBus
Он универсален, будь то Vue, React, Angular или нативные проекты.