Общее решение для создания компонентов формы на основе конструктора Vue

внешний интерфейс Vue.js Ant Design

В обычном внешнем бизнесе, будь то официальный веб-сайт, страница дисплея или внутренняя операционная система, форма неотделима, и на нее возлагается большая часть работы по сбору данных. Так что как лучше реализовать это важный вопрос в обычной работе.

При использовании платформы Vue для развития бизнеса каждая независимая визуальная/интерактивная область на странице будет разделена на компонент, а затем новая страница будет составлена ​​путем свободной комбинации нескольких компонентов. Например

<template>
  <header></header>
  ...
  <content></content>
  ...
  <footer></footer>
</template>

Когда действие пользователя запускает форму (например, регистрация, создание контента и т. д.), ожидайте появления всплывающего окна на странице.Fromкомпоненты. Обычная практика состоит в том, чтобыtemplateзаполнить один<form>компоненты используются для разработки и контролируютсяdataсерединаUI.isOpenприйти к этомуdisplayконтроль, например, когда текущий<template>Компонентная разработка<register-form>.

<template>
  <header></header>
  ...
  <content></content>
  ...
  <footer></footer>
  ...
  <register-form v-if="UI.isOpen">
    <form-item></form-item>
    ...
    <submit-button></submit-button>
  </register-form>
</template>

У этой разработки есть небольшое преимущество,Formмежду компонентом и его родительским компонентомpropтак же как$emitОблегчить общение. Но есть и следующие недостатки:

  • текущего компонентаdataДолжен иметьUI.isOpenДля управления формой, если есть несколько форм, будет большое количество состояний для поддержания переключения формы;
  • Если форма всплывает несколько раз, возможно, необходимоdataсбросить;
  • Вопреки идее компонентизации, форма не принадлежит текущей странице, это всего лишь результат, вызванный поведением пользователя.

Чтобы устранить вышеуказанные дефекты, а также иметь преимущества удобного общения, в этой статье используетсяVue.extendоригинал<form>компоненты вmethod function, и сохранить текущий компонентmethod, когда пользователь запускает его, монтирует его на странице и автоматически выходит из системы, когда он закрыт.

пример

Демонстрационный адрес:Демонстрационный пример

Кодовый адрес:FatGe github

  • Компоненты приложения
<template>
  <div id="app">
    <el-button 
        type="primary" icon="el-icon-edit-outline"
        @click="handleClick"
    >注册</el-button>
  </div>
</template>

<script>
import register from './components/register'
import { transform } from './transform'

export default {
  name: 'App',
  methods: {
    register: transform(register),

    handleClick () {
      this.register({
        propsData: { name: '皮鞋' },
        done: name => alert(`${name}牛B`)
      })
    }
  }
}
</script>

когда<el-button>Когда срабатывает событие клика, вызовитеregisterметод монтирования компонента формы на странице.

  • Компонент формы
<template>
  <div class="mock" v-if="isVisible">
    <div class="form-wrapper">
       <i class="el-icon-close close-btn" @click.stop="close"></i>

       ...<header />
       ...<content />

        <div class="footer">
            <el-button 
                type="primary"
                @click="handleClick"
            >确定</el-button>

            <el-button 
                type="primary"
                @click="handleClick"
            >取消</el-button>
        </div>
    </div>
  </div>
</template>

<script>
export default {
  porps: { ... },

  data () {
    return {
      isVisible: true
    }
  },
    
  watch: {
    isVisible (newValue) {
      if (!newValue) {
        this.destroyElement()
      }
    }
  },
    
  methods: {
    handleClick ({ type }) {
      const handler = {
        close: () => this.close()
      }
    },
    destroyElement () {
      this.$destroy()
    },
    close () {
      this.isVisible = false
    }
  },
  
  mounted () {
    document.body.appendChild(this.$el)
  },
    
  destroyed () {
    this.$el.parentNode.removeChild(this.$el)
  }
}
</script>

Не поддерживается в компоненте приложения<form>Состояние компонента, его открытие или закрытие поддерживается только в его собственномdataсередина.

принцип

Наиболее важным шагом в приведенном выше коде являетсяtransformфункция, которая преобразует исходный `

отsingle-file componentsпревратился вmethod function, принцип такой

const transform = (component) => {
  const _constructor = Vue.extend(component)
  return function (options = {}) {
    const {
      propsData
    } = options
    let instance = new _constructor({
      propsData
    }).$mount(document.createElement('div'))
    return instance
  }
}

первое использованиеVue.extend(options)Создавать<Form/>подкласс компонента

const _constructor = Vue.extend(component)

потомreturn function, его функция:

  • Буду<form />компоненты вmethod
  • существуетmethodПри вызове компонентинстанцияи пройтиpropsData
const {
  propsData
} = options
let instance = new _constructor({
  propsData
}).$mount(document.createElement('div'))

Чтобы иметь возможность управлять созданным компонентом, выберитеinstanceвернуть.

Когда компонент создается, он просто монтируется вdocument.createElement('div')на странице, но он не смонтирован на странице, поэтому его нужноappendChildна страницу. Для лучшей семантики выберите завершение его монтажа на странице в течение жизненного цикла компонента. При создании экземпляра компонент срабатываетmountedжизненный цикл, поэтому при срабатывании его можно установить наdocument.body, следующим образом

mounted () {
  document.body.appendChild(this.$el)
}

При монтировании должен быть выход из системы. Соответствующий жизненный цикл должен бытьdestroyed,так

method: {
  destroyElement () {
    this.$destroy()
  }   
},
destroyed () {
  this.$el.parentNode.removeChild(this.$el)
}

Время, когда компонент вышел из системы, тесно связано с его отображением на странице, когда<form />Когда он не виден на странице, необходимо выйти из системы

watch: {
  isVisible (newValue) {
    if (!newValue) {
      this.destroyElement()
      // 如果需要添加过渡动画
      // this.$el.addEventListener('transitionend', this.destroyElement)
    }
  }
}

Общий компонент Form имеет две функции:

  • done: подтверждает от имени пользователя;
  • отмена: отмена от имени пользователя;

При выполнении или отмене могут быть соответствующие изменения в компоненте APP, поэтому после создания экземпляра компонента используйте$onследить за соответствующимdoneсобытия иcancelмероприятие.

done && inlineListen({
  method: 'done',
  options,
  instance
})
cancel && inlineListen({
  method: 'cancel',
  options,
  instance
})

вinlineListenФункция может облегчить последующее добавление другихevent, чей код

const inlineListen = ({
  method,
  options,
  instance
}) => {
  let listener = `on${method}`
  instance[listener] = options[method]
  instance.$on(method, function (data) {
    this[listener](data)
  })
}

Вышеупомянутая схема также может быть инкапсулирована какPromiseформа, как показано ниже

export const transform = (component) => {
  const _constructor = Vue.extend(component)
  return function (options = {}) {
    const {
      propsData
    } = options

    return new Promise((resolve, reject) => {
      let instance = new _constructor({
        propsData
      }).$mount(document.createElement('div'))

      instance.$on('done', data => resolve(data))
    })
  }
}

использовать

может принадлежать вышеперечисленному<Form/>общественныйdataтак же какmethodнезависимый, затем пройтиmixinsв каждую форму, например.

export default {
  data() {
    return {
      visible: true
    }
  },
  watch: {
    visible(newValue) {
      if (!newValue) {
        this.destroyElement()
      }
    }
  },
  mounted() {
    document.body.appendChild(this.$el)
  },
  destroyed() {
    this.$el.parentNode.removeChild(this.$el)
  },
  methods: {
    destroyElement() {
      this.$destroy()
    },
    close() {
      this.visible = false
    }
  }
}

пройти сноваmixinsсмешать.

<script>
import popupWin from '../mixins/popup-win'

export default {
  mixins: [popupWin],

  data () {
    return {
      input: '',
      gender: 1
    }
  },
  methods: {
    handleClick ({ type }) {
      const handler = {
        close: () => this.close(),
        confirm: () => {
          const { input } = this
          this.$emit('done', input)
        }
      }
    }
  }
}
</script>

При звонке просто

export default {
  name: 'App',
  methods: {
    register: transform(register),

    handleClick () {
      this.register({
        propsData: {
          ...
        },
        // done: data => function
        done () {
            // 外部关闭
            this.close()
        }
      })
    }
  }
}

PS: Если бизнес-сценарий требует, когда форма внешнего управления закрыта, нужно только изменитьdone functionизcontext, то есть,thisуказатель на<Form/>.

Суммировать

через вышеуказанноеtransformфункция, которая преобразует исходные внедренные компоненты в императивные, что упрощает обслуживание состояния страницы.mixinsсмешать на публикеdataтак же какmethod, что упрощает разработку компонентов формы. Вышеупомянутый метод также можно использовать для разработки таких компонентов, как всплывающее уведомление, оповещение, подтверждение и т. д.

Vue.prototype.method = transform(Toast-Component) 

Оригинальное заявление: Данная статья является оригинальной, при перепечатке просьба указывать источник.