ああ、これらのモヌダルりィンドりたたはVueJsのレンダリング関数が奜きな理由

みなさんこんにちは
私の最初の出版物は䞍快な埌味でした。 私はこの誀解を正すこずを玄束し、あなたの法廷にVueJsに関する最初の蚘事のレッスンを提䟛したす。 圹に立぀こずを願っおいたす。 倚くの考え、倚くの経隓。 私は他の人の蚘事、教蚓に沿っお勉匷しおきたした。 知識を共有する時です。
そしお、モヌダルりィンドりを䜜成したす。 はい、圌らは再びです。 しかし、私の最初の私のものではない出版物で説明されおいるほど単玔ではありたせん。

Vueの倚くはすでに䜜成されおいたす。 みんな䜿甚したした。 そしお、明らかに、楜噚の所有暩の特定のレベルこの堎合はVue に達したら、すぐに自転車を䜜りたいず思うでしょう。 そしお、私は芏則の䟋倖でもありたせんでした。

利甚可胜なすべおのモヌダルコンポヌネントのうち、䞻にこれを䜿甚したした-Vuedals 。
しかし、私はそれをアップグレヌドするこずにしたした。 原則ずしお、 EventBusずりィンドりの開閉に関連するむベントの盞互䜜甚のみがコアから残りたした。 メむンコンポヌネントが曞き盎されおラッパヌコンテナヌになり、新しいコンポヌネントモヌダルりィンドり自䜓が远加されたした。
しかし、たず最初に。 そしお、蚘事は非垞に倧きくなり、誰がマスタヌするでしょう、そのハンサム:)

基本的に、すべおの䟋のモヌダルりィンドりは、このスタむルで呌び出されたす。

<template> <button @click="visible = true">Show modal</button> <modal :show="visible"> <div>  </div> </modal> </template> <script> export default { data() { return { visible: false } } </script> 

すべおが矎しいようです。 しかし

このアプロヌチの欠点は䜕ですか

たず、モヌダルりィンドりテンプレヌトは芪コンポヌネント内にあり、芪コンポヌネントず呌ばれたす。 たた、りィンドりコンテキストは芪から分離されおいたせん。 必ずしも䟿利で必芁なわけではありたせん。
次に、同じりィンドりが耇数の堎所で䜿甚されおいる堎合、コヌドを耇補する必芁がありたす。 ぶんぶんうんじゃない

第䞉に、これはおそらく最も重芁な欠点です-モヌダルりィンドりは、ペヌゞたたは他のVueコンポヌネント内でのみ䜿甚できたすが、 Vuex 、 Routerなどの堎所では䜿甚できたせん。 たずえば、䜕らかのむベントでルヌタヌたたはストアからモヌダルログむン/登録りィンドりを呌び出す必芁がありたす。 䟋はミリオンによっお䞎えるこずができたす。

したがっお、パラメヌタヌを䜿甚しお関数を呌び出し、次の圢匏の「生の」コンポヌネントを枡すこずでりィンドりを開閉するずきに、 Vuedalsが䜿甚するアプロヌチ-

 { name: 'simple-modal', props: ['test'], template: "<div>{{test}}</div>" } 

たたは倖郚からむンポヌトした本栌的なものが奜きでした。
より倚くの制埡、再利甚オプション、およびそのようなりィンドりをほがどこからでも呌び出すこずができたす。

䞀般的にはこのように芋えたすが、 たずえば 、アプリケヌションにむンポヌトしおルヌトAppコンポヌネントに貌り付けるModalWrapperコンポヌネントがありたす。 䞋のどこか。

次に、どこでもthis。$ Modals.openメ゜ッド{componentSimpleModal、title 'Simple modal'}を呌び出したす。ここで、 ModalWrapperでレンダリングされるモヌダルりィンドりを衚瀺および衚瀺するりィンドりずコンポヌネントの蚭定を転送したす。

りィンドりでのすべおの操䜜䞭に発生するむベントの束があり、これらのむベントはEventBusを䜿甚しお制埡され、それらを聞いお䜕らかの圢で反応するこずができたす。

これは、情報を孊習しやすくするための入力です。 基本的に、この蚘事はVueの初心者向けです。 しかし、私はいく぀かの興味深い魅力的な瞬間があるこずを願っおいたす。

途䞭でいく぀かのコヌドずコメントをスロヌしたす。 最埌に䟋ず゜ヌスぞのリンクがありたす。

さお、メむンファむルから始めたしょう-

index.js
 import Bus from './utils/bus'; import ModalWrapper from './modal-wrapper'; import Modal from './modal' const VuModal = {} VuModal.install = (Vue) => { Vue.prototype.$modals = new Vue({ name: '$modals', created() { Bus.$on('opened', data => { this.$emit('modals:opened', data); }); Bus.$on('closed', data => { this.$emit('modals:closed', data); }); Bus.$on('destroyed', data => { this.$emit('modals:destroyed', data); }); this.$on('new', options => { this.open(options); }); this.$on('close', data => { this.close(data); }); this.$on('dismiss', index => { this.dismiss(index || null); }); }, methods: { open(options = null) { Bus.$emit('new', options); }, close(data = null) { Bus.$emit('close', data); }, dismiss(index = null) { Bus.$emit('dismiss', index); } } }); Vue.mixin({ created() { this.$on('modals:new', options => { Bus.$emit('new', options); }); this.$on('modals:close', data => { Bus.$emit('close', data); }); this.$on('modals:dismiss', index => { Bus.$emit('dismiss', index); }); } }); } if (typeof window !== 'undefined' && window.Vue) { window.Vue.use(VuModal); } export default VuModal; export { ModalWrapper, Modal, Bus } 


その䞭で、モヌダルプリモヌダルりィンドりに䜿甚されるコンポヌネントをむンポヌトしたす。

  1. ModalWrapper.js-りィンドりを衚瀺するための䞀般的なラッパヌ
  2. Modal.js-モヌダルりィンドり自䜓のコンポヌネント。 オリゞナルのVuedalにはありたせん。 盎接䜿甚する必芁はありたせん。 いずれにせよ、それは内郚で機胜したす。 劇に沿っお、あなたは耳でこの気味を芋るでしょう、そしお、なぜ私がそれを加えたのかが明らかになるでしょう。
  3. Bus.js-ラッパヌコンポヌネント ModalWrapper 、モヌダルりィンドり Modal 、およびVueJsアプリケヌション間の通信甚のEventBus 。

Bus.jsコヌドをすぐに提䟛し、そこで䜕が起こるかを説明したす。 前述したように、 EventBusは元の状態のたたになりたした。

Bus.js
 let instance = null; class EventBus { constructor() { if (!instance) { this.events = {}; instance = this; } return instance; } $emit(event, message) { if (!this.events[event]) return; const callbacks = this.events[event]; for (let i = 0, l = callbacks.length; i < l; i++) { const callback = callbacks[i]; callback.call(this, message); } } $on(event, callback) { if (!this.events[event]) this.events[event] = []; this.events[event].push(callback); } } export default new EventBus(); 


ここでは、むベント $ on をサブスクラむブし、むベントをトリガヌ $ emit できるEventBusのシングルトンむンスタンスを䜜成したす。 説明する特別なものはないず思いたす。 EventBusはコヌルバックを収集し、必芁に応じおそれらを呌び出したす。 さらに、すべおのコンポヌネントをどのように接続するかが明確に理解できるようになりたす。

そしお今、index.js

ここで、デフォルトのデフォルトのむンストヌル関数を゚クスポヌトしたす-りィンドりをアプリケヌション Vue.useを䜿甚ずModalWrapper 、 ModalおよびBusコンポヌネントに接続したす。 ブラりザのスクリプトタグを介しおVueUniversalModalを接続する堎合、ペヌゞ䞊のグロヌバルVueJが接続されおいる堎合、コンポヌネントをアクティブにしたす。

そしお順番に

$モヌダル
 Vue.prototype.$modals = new Vue({ name: '$modals', created() { Bus.$on('opened', data => { this.$emit('modals:opened', data); }); Bus.$on('closed', data => { this.$emit('modals:closed', data); }); Bus.$on('destroyed', data => { this.$emit('modals:destroyed', data); }); this.$on('new', options => { this.open(options); }); this.$on('close', data => { this.close(data); }); this.$on('dismiss', index => { this.dismiss(index || null); }); }, methods: { open(options = null) { Bus.$emit('new', options); }, close(data = null) { Bus.$emit('close', data); }, dismiss(index = null) { Bus.$emit('dismiss', index); } } }); 


ここでは、 $ modalsず呌ばれるVueの  プロトタむプを介した グロヌバルVueJsむンスタンスにフックしたす。

䜜成されたメ゜ッドアプリケヌションの開始盎埌に開始で、 EventBusを、 開いた りィンドりを開く、 閉じた りィンドりを閉じる、 砎棄した りィンドりがない、 ModalWrapperを削陀するむベントに眲名したす。 これらのむベントが発生するず、EventBusはmodals open 、 modalsclosed、およびmodalsdestroyedむベントを$ modalsコンポヌネントに出力したす。 VueJsが個人的に利甚可胜な堎合はい぀でも、これらのむベントを聞くこずができたす。

䞀般に、䞀郚は完党にオプションであったため、最初はこれらの通信の半分を捚おたいず思っおいたしたが、考えた埌、それを残したした。 たずえば、モヌダルりィンドりの統蚈情報を収集する堎合に圹立ちたす。 そしお初心者は、この䞀芋混乱した$ on 、 $ emit-呌び出しで、おそらく自分で䜕かを理解するでしょう。

さらにこれ。$ On ...

ここでは、 $ modalsコンポヌネント自䜓によるむベントリスナヌnew 、 close 、 dismissを有効にし たす 。 これらのむベントが発生するず、 $ modalsコンポヌネントの察応するメ゜ッドが呌び出されたす。 りィンドりを開く open 、閉じる close 、キャンセル dismiss したす。

ご芧のように、りィンドりを閉じるには、2぀の方法がありたす-同じオペラから閉じるキャンセルたたはブルゞョア-キャンセル-および閉じる 閉じる。 違いは、 closeを介しおモヌダルりィンドりを閉じるず 、新しいモヌダルりィンドりのオプションにフックするonCloseコヌルバック関数にデヌタを転送できるこずです埌で怜蚎したす。

そしお、実際には$ modalsコンポヌネントのopen 、 close 、およびdismissメ゜ッド 。 それらの䞭で、 ModalWrapperの新しい 、 close 、 dismissむベントであるEventBusを実行したす。 そこで、すべおの魔法が起こりたす。

そしお、index.jsファむルのむンストヌル機胜の最埌。

 Vue.mixin({ created() { this.$on('modals:new', options => { Bus.$emit('new', options); }); this.$on('modals:close', data => { Bus.$emit('close', data); }); this.$on('modals:dismiss', index => { Bus.$emit('dismiss', index); }); } }); 

ここでは、 䜜成されたメ゜ッドをVueミックスむンを介しおすべおのVueコンポヌネントに拡匵し、起動時にコンポヌネントがモヌダルnew 、 modalscloseおよびmodalsdismissむベントをリッスンできるようにし、EventBusを介しおそれらが呌び出されるず、察応するむベントをModalWrapperで再床開始したす

モヌダルりィンドりを制埡するには、これらすべおの地獄のような呌び出しがここで必芁です。 たた、 open 、 close、およびdismissむベントをトリガヌするための4぀のオプションを提䟛したす 。

アプリケヌションでモヌダルりィンドりを呌び出す最初の方法

 this.$modals.open(options) 

2番目の方法
 this.$modals.$emit('new', options) 

第䞉

 this.$emit('modals:new', options) 

4番目このメ゜ッドの堎合、Bus.jsをむンポヌトする必芁がありたすが、これにより、 Vueコンポヌネントからではなく、任意のスクリプトからりィンドりを呌び出すこずができたす

 Bus.$emit('new', options) 

たあ、 近い 、アナロゞヌで华䞋したす。

ここで、圌らが蚀うように-「味ず色ぞ」。

次の患者はModal.jsか、簡単な方法を探しおいたせん


より楜しいコヌドが远加されたす。 最近、コンポヌネント暙準圢匏ずjsx圢匏の䞡方でレンダリング関数を䜿甚しおいたす 。 それらがレンダリングのためのより倚くの機䌚を提䟛するこずに気づいたずき、私はどこでもそれを䜿い始めたした。 レンダリング関数を䜿甚するず、 Javascriptのすべおの機胜に加えお、 vNodeを備えたクヌルな内郚VueJsキッチンが具䜓的なボヌナスをもたらしたす。 それらが登堎したずき、私はそれらをどういうわけか質問し、 テンプレヌトテンプレヌトにコンポヌネントを描画し、䜕のために描画し続けたした。 しかし、今、私は犬が埋葬されおいる堎所を知っおいたす。

モヌダルは、モヌダルりィンドり自䜓をレンダリングする本栌的なコンポヌネントです。 入力パラメヌタヌの束がありたす。

modal.js-小道具
  props: { title: { //   type: String, default: '' }, className: { //  css-    type: String, default: '' }, isScroll: { //  ,   -       type: Boolean, default: false }, escapable: { // dismiss()    Esc- type: Boolean, default: false }, dismissable: { // dismiss()               () type: Boolean, default: true }, fullscreen: { //   type: Boolean, default: false }, isTop: { //      type: Boolean, default: false }, isBottom: { //      type: Boolean, default: false }, isLeft: { //       type: Boolean, default: false }, isRight: { //       type: Boolean, default: false }, center: { //    type: Boolean, default: false }, size: { //   () type: String, default: 'md' }, bodyPadding: { // padding-  body - ,     type: Boolean, default: true } }, 


圌は、コヌド内のすべおのパラメヌタヌに぀いおコメントしお、より明確にしたした。 そしお、フットクロスが機胜しないように、コヌドをスポむラヌにスロヌしたす。 たくさんのテキスト。

次

 import CloseIcon from './close-icon' export default { name: 'vu-modal', componentName: 'vu-modal', ... } 

最初に、 SVG圢匏でレンダリングする機胜コンポヌネントの圢匏で十字アむコンをむンポヌトしたす。

close-icon.js
 export default { name: 'close-icon', functional: true, render(h) { return h('svg', { attrs: { width: '12px', height: '12px', viewBox: '0 0 12 12', xmlSpace: 'preserve' } }, [ h('line', { attrs: { x1: 1, y1: 11, x2: 11, y2: 1 }, style: { strokeLinecap: 'round', strokeLinejoin: 'round', } }), h('line', { attrs: { x1: 1, y1: 1, x2: 11, y2: 11 }, style: { strokeLinecap: 'round', strokeLinejoin: 'round', } }) ]) } } 


なぜ私は圌女に気付いたのか、私も知らない

次に、 nameパラメヌタヌ-これは暙準的な動きです。

しかし、ここではcomponentNameは偶然ではありたせん。 レンダリング時にModalWrapperでさらに必芁になりたす。

そしお、蚈算されたパラメヌタヌpropsData 

 export default { ... computed: { propsData() { return (this.$parent.$vnode.data.props && this.$parent.$vnode.data.props.vModal) ? this.$parent.$vnode.data.props.vModal : this.$props } } } 

ここはもっず耇雑です。

しかし、問題はこれです。 元のVuedalでは、すべおのりィンドりは䞊蚘の4぀のメ゜ッドを䜿甚しお呌び出されたす。 それぞれに、りィンドりに衚瀺するコンポヌネントずりィンドりパラメヌタヌを枡す必芁がありたすこれらはすべお、受信モヌダルパラメヌタヌに含たれ、さらにいく぀かの新しいパラメヌタヌが远加されたす。 たた、アプリケヌションの異なる郚分で同じりィンドりを実行したい堎合は、毎回りィンドりパラメヌタヌディメンション、その他の蚭定を枡したす。 これも重耇です。 はい、長い間混乱しないでください。 そしお、私たちプログラマヌは、生き物はコアで非垞に怠け者です。 したがっお、このモヌダルコンポヌネントが䜜成されたした。

これで、次のようなモヌダルりィンドりコンポヌネントを䜜成できたす。

simple-modal.js
 <template lang="html"> <vu-modal title="Test modal" :isScroll="true" size="p50" :center="true" :escapable="true"> <div slot="header" style="display: flex; justify-content: left; align-items: center;" v-if="header"> <div style="padding-left: 10px">Simple modal</div> </div> <div> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quia consequuntur minus sint quidem ut tenetur dicta sunt voluptates numquam. Eum totam ex maxime aut recusandae quae laborum fugit ab autem.</p> </div> <div slot="footer"> <button class="uk-button uk-button-smaller uk-button-primary" @click="close">Cancel</button> </div> </vu-modal> </template> <script> export default { name: 'simple-modal', props: { lorem: { type: Boolean, default: true } } }; </script> 


぀たり、暙準コンポヌネントです。 Modal  vu-modal によっおラップされたす。 このvu-modalに、必芁なパラメヌタヌを枡したす。 これらは、このりィンドりのデフォルト倀になりたす。

そしお、このりィンドりを次のように呌び出したす。

 import SimpleModal from './modals/simple' ... this.$modals.open({ component: SimpleModal }) 

必芁なりィンドり蚭定のデフォルト倀はすべお、 vu-modalラッパヌから取埗した同じSimpleModalコンポヌネントから自動的に取埗されたす。 必芁な蚭定でりィンドりコンポヌネントを䜜成した埌、蚭定を気にせずにどこでも䜿甚できたす。 さらに、これらのデフォルト倀を再割り圓おする必芁がある堎合、このりィンドりが呌び出されるずきに必芁な倀を指定したす。

 import SimpleModal from './modals/simple' ... this.$modals.open({ component: SimpleModal, center: false }) 

これで、 䞭倮のパラメヌタヌがりィンドりテンプレヌトで指定されたデフォルトのパラメヌタヌSimpleModalに眮き換わりたす。

぀たり、パラメヌタヌをマヌゞマヌゞするずきの優先順䜍は次のずおりです。


䜎いほど重芁です。

そのため、 vu-modalコンポヌネントの蚈算されたpropsDataプロパティは、 vu-modalのこのむンスタンスが䜕らかのコンポヌネントのラッパヌ SimpleModal であるかどうかを考慮しお、正しい入力パラメヌタヌ props を返したす。
これを行うには、 ModalWrapperでりィンドりをレンダリングするずきに、このりィンドりのコンポヌネントがvu-modalでラップされおいる堎合、愚かな支柱をvModalずいう名前で転送したす。そうでない堎合は、通垞の支柱を転送したす。

ただし、コンポヌネントがvu-modalにラップされおいる堎合、 小道具をレンダリングするずきにこの芪コンポヌネント SimpleModal に分類されるため、芪コンポヌネントにvModalずいう名前の入力パラメヌタヌがあるかどうかを確認したす。 存圚する堎合、これらの倀を取埗したす。それ以倖の堎合は、暙準propsを取埗したす。

そしお、 これをチェックしたせん$ Parent。$ Options.propsData 、しかしこれ。$ Parent。$ Vnode.data.propsは、芪コンポヌネントのpropsに vModalパラメヌタヌがない堎合、これをレンダリングするずきにこれを芋るこずができるvModalは$ parent。$ vnode.data.propsです。 これには、䟋倖なく枡したすべおのパラメヌタヌが含たれたす。 そしお、それらはフィルタリングされ、䜙分な郚分は砎棄されたす。

このコヌドをもう䞀床教えおください。これは、思考ず混同しないように小さいものです。

 export default { ... computed: { propsData() { return (this.$parent.$vnode.data.props && this.$parent.$vnode.data.props.vModal) ? this.$parent.$vnode.data.props.vModal : this.$props } } } 

今、おそらくすべおが明確ではない。 倚くの情報がありたすが、倚くのレッスンのようにすべおが暙準ではありたせん。 私はこの皮の蚘事を初めお曞いおいたすが、どのように教えるのが最善かはただ明確ではありたせん。 おそらく倚くの人がVueの内郚を掘り䞋げおいたすが、それに぀いお曞く人はほずんどいたせん。 長い間、私はそのような瞬間に関する情報を探したした。 私は䜕かを芋぀け、残りを自分で遞びたした。 そしお、私はそのようなこずに぀いお話したいです。

しかし、 ModalWrapperを分解するず、より明確になりたす。 そこで、ステンドプロップを䜜成しお窓に送りたす。

さお、 モヌダルコンポヌネントのレンダリング機胜 vu-modal が残っおいたす 。

レンダリングh "
 render(h) { const { dismissable, title, isScroll, fullscreen, isTop, isBottom, isLeft, isRight, center, size, className, bodyPadding } = this.propsData const closeBtn = dismissable ? h('div', { class: 'vu-modal__close-btn', on: { click: () => {this.$modals.dismiss()} } }, [h(CloseIcon)]) : null const headerContent = this.$slots.header ? this.$slots.header : title ? h('span', {class: ['vu-modal__cmp-header-title']}, title) : null const header = headerContent ? h('div', { class: ['vu-modal__cmp-header'] }, [ headerContent ]) : null const body = h('div', { class: ['vu-modal__cmp-body'], style: { overflowY: isScroll ? 'auto' : null, padding: bodyPadding ? '1em' : 0 } }, [ this.$slots.default ]) const footer = this.$slots.footer ? h('div', { class: ['vu-modal__cmp-footer'] }, [ this.$slots.footer ]) : null let style = {} let translateX = '-50%' let translateY = '0' if(center) { translateX = '-50%' translateY = '-50%' } if(isRight || isLeft) { translateX = '0%' } if((isTop || isBottom) && !isScroll && !center) { translateY = '0%' } style.transform = `translate(${translateX}, ${translateY})` return h('div', { style, class: ['vu-modal__cmp', { 'vu-modal__cmp--is-fullscreen': fullscreen, 'vu-modal__cmp--is-center': center, 'vu-modal__cmp--is-top': isTop && !isScroll && !center, 'vu-modal__cmp--is-bottom': isBottom && !isScroll && !center, 'vu-modal__cmp--is-left': isLeft, 'vu-modal__cmp--is-right': isRight }, isScroll && fullscreen && 'vu-modal__cmp--is-scroll-fullscreen', isScroll && !fullscreen && 'vu-modal__cmp--is-scroll', !fullscreen && `vu-modal__cmp--${size}`, className ], on: {click: (event) => {event.stopPropagation()}} }, [ closeBtn, header, body, footer ]) } 


ここでは珍しいこずは䜕もないようです。

最初に、前述のpropsDataの蚈算倀からすべおのパラメヌタヌを匕き出したす。

dismissableプロパティがtrueの堎合、 dismissむベントりィンドりのキャンセルをトリガヌする十字ボタンを衚瀺したす 。

ヘッダヌを圢成したす-headerずいう名前のスロット this。$ Slots.header がvu-modalに枡される堎合、 titleプロパティが枡される堎合、このスロットを描画したす-それを印刷したす。そうでなければ、 ヘッダヌをたったく衚瀺したせん。

デフォルトのスロット this。$ Slots.default の内容で本䜓ブロックを圢成したす。
そしお、 フッタヌ - フッタヌスロット this。$ Slots.footer が枡された堎合 。
次に、 transformのcss-プロパティの正しい倀を決定したすりィンドりのtranslatex、y 。 ぀たり、りィンドりに転送されたプロパティに応じお、パラメヌタヌXおよびYが䜿甚されたす。 そしお、レンダリング時の適切な配眮のために、この倉換をメむンりィンドりdivにレンダリングしたす。

さお、党䜓をレンダリングし、同時に必芁なクラスを蚈算したす。

さらに、メむンのdiv.vu-modal__cmp onClick-ハンドラヌでevent.stopPropagationを䜿甚しお電話を切るず、各りィンドりをラップし、クリックに応答するdiv マスクのクリックがアクティブにならないように、りィンドりのクリックが䞊にポップアップしたせんそしおdismissを呌び出したす。 そうでない堎合、マスクのこのdismissむベントが発生し、りィンドりが閉じたす。
うわヌ

最埌のコンポヌネントはModalWrapperです


modal-wrapper.jsを開始したす

むンポヌト './style.scss'
'./utils/bus'からのバスのむンポヌト
ModalCmpを「./modal」からむンポヌトしたす

゚クスポヌトのデフォルト{
名前「vu-modal-wrapper」、
デヌタ{
return {
モヌダル[]
}
}、
マりント枈み{
iftypeof document== 'undefined'{
document.body.addEventListener 'keyup'、this.handleEscapeKey
}
}、
砎壊された{
iftypeof document== 'undefined'{
document.body.removeEventListener 'keyup'、this.handleEscapeKey
}
}、

スタむルを接続したす。
style.scss
 body.modals-open { overflow: hidden; } .vu-modal { &__wrapper { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 5000; overflow-x: hidden; overflow-y: auto; transition: opacity .4s ease; } &__mask { background-color: rgba(0, 0, 0, .5); position: absolute; width: 100%; height: 100%; overflow-y: scroll; &--disabled { background-color: rgba(0, 0, 0, 0); } } &__cmp { display: flex; flex-direction: column; border-radius: 0px; background: #FFF; box-shadow: 3px 5px 20px #333; margin: 30px auto; position: absolute; left: 50%; transform: translateX(-50%); width: 650px; &--is-center { margin: auto; top: 50%; } &--is-scroll { max-height: 90%; } &--is-scroll-fullscreen { max-height: 100%; } &--is-fullscreen { width: 100%; min-height: 100%; margin: 0 0; } &--is-bottom { bottom: 0; } &--is-top { top: 0; } &--is-right { right: 0; margin-right: 30px; } &--is-left { left: 0; margin-left: 30px; } &--xl { width: 1024px; } &--lg { width: 850px; } &--md { width: 650px; } &--sm { width: 550px; } &--xs { width: 350px; } &--p50 { width: 50%; } &--p70 { width: 70%; } &--p90 { width: 90%; } &-body { padding: 1em; &::-webkit-scrollbar { width: 6px; } &::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); } &::-webkit-scrollbar-thumb { background-color: darkgrey; outline: 1px solid slategrey; } } &-header { user-select: none; border-bottom: 1px solid #EEE; padding: 1em; text-align: left; &-title { font-size: 16px; font-weight: 800; } } &-footer { border-top: solid 1px #EEE; user-select: none; padding: 1em; text-align: right; } } &__close-btn { user-select: none; position: absolute; right: 12px; top: 5px; line { stroke: grey; stroke-width: 2; } &:hover { cursor: pointer; line { stroke: black; } } } } 


モヌダル配列には、珟圚アクティブなりィンドりを保存したす。

さお、 ModalWrapperコンポヌネントをマりントおよび削陀するずき、 キヌアップハンドラヌをりィンドり  りィンドりがある堎合で切断し 、 handleEscapeKeyメ゜ッドを起動したす 。

handleEscapeKey
 handleEscapeKey(e) { if (e.keyCode === 27 && this.modals.length) { if (!this.modals.length) return; if (this.current.options.escapable) this.dismiss(); } } 


次に、 Escキヌが抌され、りィンドりがあり、珟圚の最埌に起動されたりィンドりがある堎合、 escapableプロパティはtrueになり 、この珟圚のりィンドりを閉じるdismissメ゜ッドを実行したす。

さお、おそらく最も興味深いこずが始たっおいたす。 コヌドで䜕が起きおいるのかを説明しようず思いたすが、倚分それは改善されるでしょう。

ModalWrapperを䜜成するずき、 EventBusからのむベントリスニングを有効にしたす 。 前述の$ modalsメ゜ッドで実行されるもの

䜜成枈み
 created() { Bus.$on('new', options => { //  ,   const defaults = { //    ,      Modal title: '', dismissable: true, center: false, fullscreen: false, isTop: false, isBottom: false, isLeft: false, isRight: false, isScroll: false, className: '', size: 'md', escapable: false, bodyPadding: true }; //     ! //   props-   .    . // rendered     ,      options,   Modal (vu-modal)   let instance = {} // ,       modals let rendered if(options.component.template) { //    ""   template,   Modal    ,    .     .    .    . rendered = false } else { //    render  ,    componentOptions rendered = options.component.render.call(this, this.$createElement) } //             componentName  Modal.      'vu-modal',     Modal (vu-modal) if(rendered && rendered.componentOptions && rendered.componentOptions.Ctor.extendOptions.componentName === 'vu-modal') { //      props-,       template-  vu-modal const propsData = rendered.componentOptions.propsData instance = { isVmodal: true, //      ,      options: Object.assign(defaults, propsData, options) //       } } else { instance = { isVmodal: false, //       vu-modal options: Object.assign(defaults, options) //      } } rendered = null this.modals.push(instance); //   modals Bus.$emit('opened', { //       EventBus c    index: this.$last, //    ,  instance //   }); this.body && this.body.classList.add('modals-open'); //    body    }); 


その他のむベント

閉じお华䞋
 Bus.$on('close', data => { // ,            close let index = null; if (data && data.$index) index = data.$index; //      if (index === null) index = this.$last; //   ,    this.close(data, index); //   close     }); Bus.$on('dismiss', index => { //     dismiss,      if (index === null) index = this.$last; //  ,   this.dismiss(index); //   dismiss   }); 


次にメ゜ッド

スプラむス
 methods: { splice(index = null) { //   ,    if (index === -1) return; if (!this.modals.length) return; if (index === null) //    ,    this.modals.pop(); else this.modals.splice(index, 1); if (!this.modals.length) { //    this.body && this.body.classList.remove('modals-open'); //  body   'modals-open' Bus.$emit('destroyed'); //   ,  EventBus,  ,     } } } 


閉じる
 doClose(index) { //      modals ,    splice,   if (!this.modals.length) return; if (!this.modals[index]) return; this.splice(index); }, // ,    ,  close.            close(data = null, index = null) { if (this.modals.length === 0) return; let localIndex = index; //   index  ,      ,           .      ,  -  if (index && typeof index === 'function') { localIndex = index(data, this.modals); } if (typeof localIndex !== 'number') localIndex = this.$last; //     // , ,      callback- onClose,     ,    //     onClose - ,    false,     if (localIndex !== false && this.modals[localIndex]) { if(this.modals[localIndex].options.onClose(data) === false) { return } } Bus.$emit('closed', { //   'closed'      index: localIndex, //   instance: this.modals[index], //   data //  ,   }); //  ,     ,     modals,     this.doClose(localIndex); }, 


dismissメ゜ッドでは、すべおがcloseメ゜ッドに䌌おいたす

华䞋する
 dismiss(index = null) { let localIndex = index; if (index && typeof index === 'function') localIndex = index(this.$last); if (typeof localIndex !== 'number') localIndex = this.$last; if (this.modals[localIndex].options.onDismiss() === false) return; Bus.$emit('dismissed', { index: localIndex, instance: this.modals[localIndex] }); this.doClose(localIndex); }, 


蚈算されたプロパティ

蚈算された
 computed: { current() { //   return this.modals[this.$last]; }, $last() { //   ()  return this.modals.length - 1; }, body() { //  body,  ,  /  'modals-open' if (typeof document !== 'undefined') { return document.querySelector('body'); } } } 


さお、最埌の機胜、今私のお気に入り

レンダリングh
 render(h) { //   ,    if(!this.modals.length) { return null }; //     let modals = this.modals.map((modal, index) => { //    let modalComponent //      if(modal.isVmodal) { //        Modal (vu-modal) //       props-,    vModal c    vu-modal   props-   ,    modalComponent = h(modal.options.component, { props: Object.assign({}, {vModal: modal.options}, modal.options.props) }) } else { //    Modal          ,     props-,  ,     modalComponent = h(ModalCmp, { props: modal.options }, [ h(modal.options.component, { props: modal.options.props }) ]) } //      ,     -    css //  dismissable   true,  ,   return h('div', { class: ['vu-modal__mask', {'vu-modal__mask--disabled': index != this.$last }], on: {click: () => {modal.options.dismissable && this.dismiss()}}, key: index }, [ modalComponent //     ]) }) //        return h('div', { class: 'vu-modal__wrapper', }, [ modals ]) } // ! :) 


ここに物語がありたす。長い話。次回は必芁に応じお短くしおみたす。

最埌に、情報をよりよく理解するためにりィンドりを開くためのコヌドの䟋を瀺したす。

 this.$modals.open({ title: 'Modal with callbacks', component: Example, props: { lorem: true, test: true }, onDismiss() { console.log('Dismiss ok!') } onClose(data) { if(data.ended) return false console.log('Ok!') } }) 

そしお、たずえば、りィンドりのボタンを䜿甚しお、そこにデヌタを転送するcloseを開始したす。

 this.$modals.close({ ended: true }) 

この堎合、閉じる前に、onClose コヌルバックが起動されたす。

同様に、onDismissは機胜したす。このコヌルバックは、たずえばフッタヌの[キャンセル]ボタンをクリックしたずきに、クロスボタン、りィンドりマスクをクリックするか、りィンドり内で盎接クリックするこずでトリガヌされたす。

 this.$modals.dismiss() 

その他。レンダリング機胜に぀いお。それらは確かにtemplateのコヌドほど芋栄えがよくありたせん。しかし、それらでは、テンプレヌトでは䞍可胜なこずを行うこずができたすが、おそらく、束葉杖ずレンダリング関数で埗られるよりもはるかに倚くのコヌドでできたす。そしお、で塗料成分であれば、レンダリングは非垞に慎重に倉曎された関数props-ずDATA-䟝存レンダリングし、そこからプロパティを、アップデヌトの無限のサむクルぞ行くにはそうでないリスク曎新コンポヌネント。

おそらく今のずころすべお。そしお、圌は束を打ち切りたした。しかし、私は党䜓の動きを説明したかった。次の蚘事は短くなりたす。しかし、私が話したいニュアンスもありたす。

そしお、このラむンに䜏んでいたみんなに感謝したす

PS ここにりィンドりの䟋がありたす。゜ヌスコヌドを含むGithubぞのリンクもありたす。ロシア語でもドキュメントを远加したす。

Source: https://habr.com/ru/post/J350232/


All Articles