Применение шаблонов проектирования в Vue (5)

Vue.js

предисловие

Расположение каталога:
Применение шаблонов проектирования в Vue (1)
Применение шаблонов проектирования в Vue (2)
Применение шаблонов проектирования в Vue (3)
Применение шаблонов проектирования в Vue (4)
Применение шаблонов проектирования в Vue (5)
Применение шаблонов проектирования в Vue (6)
Применение шаблонов проектирования в Vue (7)

Зачем писать эти статьи. так какШаблон проектирования — это набор повторяющихся, наиболее известных, классифицированных сводок опыта разработки кода.(Из энциклопедии Baidu), так же, как мы хотели изучить очарование и шаблоны дизайна, накопив некоторую работу.
Сценарии приложений, представленные в этой серии статей, чтобы помочь в объяснении, являются реальными сценариями приложений в действии, конечно, они не могут охватывать все аспекты, но они также охватывают общие бизнес-сценарии по аналогии.



Эта статья может немного отличаться от предыдущей.В предыдущих статьях нужно было создать множество объектов (компонентов) для достижения нашей цели, и главный герой этой статьи — позволить нам уменьшить шаблон объекта-приспособленца.
Определение (из сети):

В шаблоне Flyweight используются методы совместного использования, позволяющие повторно использовать одни и те же или похожие объекты. То есть добиться совместного использования кода одинаковых или похожих объектов.

Сценарии использования (из энциклопедии Baidu):

Если приложение использует большое количество объектов, и эти объекты вызывают большие накладные расходы на хранилище, вы можете рассмотреть возможность использования шаблона Приспособленца.

1. Спрос

Скриншот из официальной документации iView (компонент Message)

Считается, что компонент «Сообщение» всем знаком, интересно, реализовали ли вы его сами.

2. Анализ спроса

Компонент сообщения имеет следующие характеристики:

  • такой же способ взаимодействия
  • Есть три типа:success,warning,error, соответствующий трем различным эффектам страницы: значок подсказки, стиль фона, стиль шрифта
  • Получить текст напоминания

Знать:

Взаимодействие — всплывающее окно, скрытие, владение общими объектами

Значок подсказки, стиль фона, стиль шрифта для обеспечения настраиваемого интерфейса

Унифицировать с помощью API

3. Дизайн и реализация

нормальное использованиеthis.$Message.success(),this.$Message.warning(),this.$Message.error()Итак, нам нужно расширить vue в виде плагина vue.prototype

//Message.js 伪代码
export default {
  install (Vue) {
    // 扩展Vue的`prototype`
    Vue.prototype.$Message = {
      success (text) {
        // 通常我们可能如下操作,每次new一个新的组件对象
        const Dialog = new Vue({
          ...
        })
        document.body.appendChild(Dialog.$el)
      },
      warning (text) {
        // 同上,new一个新的组件对象
        const Dialog = new Vue({
          ...
        })
        document.body.appendChild(Dialog.$el)
      },
      error (text) {
        // 同上,new一个新的组件对象
        const Dialog = new Vue({
          ...
        })
        document.body.appendChild(Dialog.$el)
      }
    }
  }
}

Как показано в приведенном выше примере, каждый раз, когда используется компонент «Сообщение», требуется новый диалог.Далее мы используем идею режима облегченного веса для достижения цели уменьшения объектов компонента.

//Message.js 伪代码
export default {
  install (Vue) {
    // 在使用插件Vue.use(Message)时实例化一个Dialog组件对象
    const Dialog = new Vue({
      data () {
        return {
          icon: '',
          fontStyle: '',
          backgroundStyle: '',
          text: ''
        }
      }
      ...
    })
    
    // 扩展Vue的`prototype`
    Vue.prototype.$Message = {
      success (text) {
        // 改变Dialog的data.xx的值触发Dialog的更新
        Dialog.icon = successIcon
        Dialog.fontStyle = successFontStyle
        Dialog.backgroundStyle = successBackgroundStyle
        Dialog.text = text
        // 获取Dialog的最新DOM添加到body标签中
        document.body.appendChild(Dialog.$el)
      },
      warning (text) {
        // 同上
        ...
        document.body.appendChild(Dialog.$el)
      },
      error (text) {
        // 同上
        ...
        document.body.appendChild(Dialog.$el)
      }
    }
  }
}

4. Результаты

Говорят, что работа ориентирована на результат, теперь давайте посмотрим, каких результатов добился наш дизайн.

Диалог будет вызываться только при инициализации проектаnewОднажды, каждый раз, когда вы используете компонент Message для получения DOM компонента, изменяя состояние диалога, легко понять, что стоимость нового компонента намного выше, чем стоимость обновления компонента.

По сравнению с обычной реализацией недостатком является то, что она будет выполняться, даже если она не используется.new Dialog()и занять память

Пять, с полной реализацией (пример)

Если есть ошибка, пожалуйста, простите меня

import './index.scss'

let zIndex = 2001;

export default {
  install (Vue) {
    const Dialog = new Vue({
      data () {
        return {
          text: '这是一个提示',
          icon: 'icon-waiting',
          iconColor: '#308AFE',
          background: '#ddd'
        }
      },
      render (h) {
        zIndex++
        const selfStyle = {
          background: this.background,
          zIndex
        }
        return h('div',
          {
            class: 'm-message',
            style: selfStyle
          },
          [
            h('i', {
              style: {marginRight: '8px', color: this.iconColor},
              class: `iconfont ${this.icon}`
            }),
            this.text
          ]
        )
      }
    }).$mount()

    function appendDialog(message, icon, iconColor, bgColor, time = 3) {
      Dialog.text = message
      Dialog.icon = icon
      Dialog.iconColor = iconColor
      Dialog.background = bgColor
      let timer = ''
      let element = document.createElement('div')
      Dialog.$nextTick(() => {
        element = Dialog.$el.cloneNode(true)
        document.body.appendChild(element)
      })
      if(time > 0) {
        timer = setTimeout(() => {
            element.classList.add('outer')
            setTimeout(() => {
              document.body.removeChild(element)
            }, 500);
            clearTimeout(timer)
        }, time * 1000);
      }
    }

    Vue.prototype.$message = {
      tips (message, time) {
        appendDialog(message, 'icon-waiting', '#308AFE', '#ADD8F7', time)
      },
      warning(message, time) {
        appendDialog(message, 'icon-warn', '#FFAF0D', '#FCCCA7', time)
      },
      success(message, time) {
        appendDialog(message, 'icon-success', '#36B37E', '#A7E1C4', time)
      },
      error(message, time) {
        appendDialog(message, 'icon-error', '#E95B5B', '#FFF4F4', time)
      },
      destory() {
        document.querySelectorAll('.m-message').forEach(ele => ele.remove())
      }
    }
  }
}

6. Резюме

Вспомните сценарий, который чаще всего используется при объяснении паттерна легковеса.

有男女衣服各50套,现在要给这些衣服拍照怎么办呢?

土豪做法:new 100个模特对象一人穿一套慢慢拍,有钱任性(内存占有率高)
理性做法:new 一个男模特和一个女模特拍完一套换一套接着拍(暴露一个换衣服的接口),
         也没差,主要是省钱(对象从100个减少为2个)

Студенты, знакомые с шаблонами проектирования, могут подумать, что эта сцена не очень хороша Я согласен с вашей точкой зрения, но я думаю, что изучение шаблона Flyweight приемлемо.
Конкретная схема реализации компонента Message не отвергает и не рекомендует метод из этой статьи (хахаха~)

Обновление: я обнаружил, что компонент MessageBox elemnet-ui представляет собой аналогичную идею.портал


Реализация этой статьи также применима к реакции, почему в статье в качестве вопроса используется vue? Шаблон Vue может заставить нас чувствовать себя немного неловко при понимании некоторых концепций, а jsx реакции можно рассматривать как написание JavaScript, чтобы быть более гибким для реализации различных концепций.
Дружеское напоминание: о применении шаблонов проектирования в Vue следует написать серию, и учащиеся, которым это нравится, не забудьте обратить внимание