2020年3月29日日曜日

Vue.js記法:Transitionのin-out表現

単一コンポネントの場合、transitionに含まれるだけ

<transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition>

<script>
new Vue({ el: '#transition-components-demo', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } } })
</script>

<style>
.component-fade-enter-active, .component-fade-leave-active { transition: opacity .3s ease; } .component-fade-enter, .component-fade-leave-to /* .component-fade-leave-active for below version 2.1.8 */ { opacity: 0; }
</style>

複数コンポネントの場合、transition-groupを使って

<div id="list-demo" class="demo"> <button v-on:click="add">Add</button> <button v-on:click="remove">Remove</button> <transition-group name="list" tag="p"> <span v-for="item in items" v-bind:key="item" class="list-item"> {{ item }} </span> </transition-group> </div>

new Vue({ el: '#list-demo', data: { items: [1,2,3,4,5,6,7,8,9], nextNum: 10 }, methods: { randomIndex: function () { return Math.floor(Math.random() * this.items.length) }, add: function () { this.items.splice(this.randomIndex(), 0, this.nextNum++) }, remove: function () { this.items.splice(this.randomIndex(), 1) }, } })

.list-item { display: inline-block; margin-right: 10px; } .list-enter-active, .list-leave-active { transition: all 1s; } .list-enter, .list-leave-to /* .list-leave-active for below version 2.1.8 */ { opacity: 0; transform: translateY(30px); }


Vue.js記法:親子Componentの相互アクセス

//Root Vue宣言
new Vue({ data: { foo: 1 }, computed: { bar: function () { /* ... */ } }, methods: { baz: function () { /* ... */ } } })

から親をアクセス

// 获取根组件的数据 this.$root.foo // 写入根组件的数据 this.$root.foo = 2 // 访问根组件的计算属性 this.$root.bar // 调用根组件的方法 this.$root.baz()

//一階層であれば、$parentを利用
this.$parent.baz()

から子をアクセス

//子Component
<base-input ref="usernameInput"></base-input>
 
new Vue({ data: { foo: 1 }, computed: { bar: function () { /* ... */ } }, methods: { // 用来从父级组件聚焦输入框 focus: function () { this.$refs.usernameInput.focus() } }
})

先祖アクセスする方法:先祖側にprovide, inject

//先祖より子孫に提供するdata/methods
provide: function () {
return { getMap: this.getMap } }
//子孫側にinjectで受取る inject: ['getMap']

イベント監視

  • $on(eventName, eventHandler) 
  • $once(eventName, eventHandler)
  • $off(eventName, eventHandler) //stop a $on event

mounted: function () { var picker = new Pikaday({ field: this.$refs.input, format: 'YYYY-MM-DD' }) //親がbeforeDestroyの時に、先にpickerをdestoryする this.$once('hook:beforeDestroy', function () { picker.destroy() }) }
//複数datapickerを利用する場合
mounted: function () { this.attachDatepicker('startDateInput') this.attachDatepicker('endDateInput') }, methods: { attachDatepicker: function (refName) { var picker = new Pikaday({ field: this.$refs[refName], format: 'YYYY-MM-DD' }) this.$once('hook:beforeDestroy', function () { picker.destroy() }) } }

※自身を参照するコンポネントは可能、だが、注意無限繰り返し。

Vue.js記法:Cacheを利用する

v-onceにより重いhtmlを一回のみloadさせる。

Vue.component('terms-of-service', { template: ` <div v-once> <h1>Terms of Service</h1> ... a lot of static content ... </div> ` })

keep-aliveで Cache current Component state

<keep-alive> <component v-bind:is="currentTabComponent"></component> </keep-alive>


必要な場合に、サーバからcomponentを取得しcacheする

//load component by component.vue/js
Vue.component( 'async-webpack-example', () => import('./my-async-component') )

// load local comonent by component.vue/js new Vue({ // ... components: { 'my-component': () => import('./my-async-component') } })

// 非同期 load base components method.
const AsyncComponent = () => ({ // 需要加载的组件 (应该是一个 `Promise` 对象) component: import('./MyComponent.vue'), // 异步组件加载时使用的组件 loading: LoadingComponent, // 加载失败时使用的组件 error: ErrorComponent, // 展示加载时组件的延时时间。默认值是 200 (毫秒) delay: 200, // 如果提供了超时时间且组件加载也超时了, // 则使用加载失败时使用的组件。默认值是:`Infinity` timeout: 3000 })

Vue.js記法:Slot記法

複数のslotを利用する場合、nameを明記しよう

<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>

slotProps

<current-user> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> </current-user>
一つだけの場合なら、:defaultは不要 <current-user v-slot="slotProps"> {{ slotProps.user.firstName }} </current-user>

複数slotなら、:slotnameが必須 <current-user> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> <template v-slot:other="otherSlotProps"> ... </template> </current-user>
slot name bind
<current-user v-slot="{ user }"> {{ user.firstName }} </current-user>
<current-user v-slot="{ user: person }"> {{ person.firstName }} </current-user>
<current-user v-slot="{ user = { firstName: 'Guest' } }"> {{ user.firstName }} </current-user>

動的slot名
<base-layout> <template v-slot:[dynamicSlotName]> ... </template> </base-layout>

v-slot:の短縮化記法:#

<base-layout> <template #header> <h1>Here might be a page title</h1> </template> <p>A paragraph for the main content.</p> <p>And another one.</p> <template #footer> <p>Here's some contact info</p> </template> </base-layout>

slot name bindの場合、slot名が必須
<current-user #default="{ user }"> {{ user.firstName }} </current-user>


Vue.js記法:Component注意点

  1. data is a function, not a property.
    data: function () { return { count: 0 } }
  2. Global registry Vue.component('my-component-name', { // ... options ... })
  3. send and receive data by prop between parent and son Vue.component('blog-post', { props: ['title'], template: '<h3>{{ title }}</h3>' }) <blog-post title="My journey with Vue"></blog-post> <blog-post title="Blogging with Vue"></blog-post> <blog-post title="Why Vue is so fun"></blog-post>
  4. v-bind component props new Vue({ el: '#blog-post-demo', data: { posts: [ { id: 1, title: 'My journey with Vue' }, { id: 2, title: 'Blogging with Vue' }, { id: 3, title: 'Why Vue is so fun' } ] } }) <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:title="post.title" ></blog-post>
  5. v-bind object prop using component template, <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post" ></blog-post> Vue.component('blog-post', { props: ['post'], template: ` <div class="blog-post"> <h3>{{ post.title }}</h3> <div v-html="post.content"></div> </div> ` })//postの新属性はいつも<blog-post>に利用可能
  6. vm.$emit( eventName, […args] )
    eventName発生した時に、指定されたfunctionを呼び出す
    Vue.component('welcome-button', { template: ` <button v-on:click="$emit('welcome')">//clickとwelcomeをbind Click me to be welcomed </button> ` }) <div id="emit-example-simple"> <welcome-button v-on:welcome="sayHi"></welcome-button> </div> new Vue({ el: '#emit-example-simple', methods: { sayHi: function () { alert('Hi!') } } })
  7. コンポネントの親子イベント連絡 Vue.component('blog-post', { props: ['post'], template: ` <div class="blog-post"> <h3>{{ post.title }}</h3> <button v-on:click="$emit('enlarge-text')">
    Enlarge text </button>
    <div v-html="post.content"></div> </div> ` }) //=親:=========================== <div id="blog-posts-events-demo"> <div :style="{ fontSize: postFontSize + 'em' }">//postFontSizeで表現 <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post" v-on:enlarge-text="postFontSize += 0.1" ></blog-post> </div> </div> new Vue({ el: '#blog-posts-events-demo', data: { posts: [/* ... */], postFontSize: 1 //親側でpostFontSizeを宣言 } }) //============================
  8. コンポネントの親子イベント連絡2:パラメータ受け渡す Vue.component('blog-post', { props: ['post'], template: ` <div class="blog-post"> <h3>{{ post.title }}</h3> <button v-on:click="$emit('enlarge-text', 0.1)">
    Enlarge text </button>
    <div v-html="post.content"></div> </div> ` }) //=親:=========================== <div id="blog-posts-events-demo"> <div :style="{ fontSize: postFontSize + 'em' }">//postFontSizeで表現 <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post" v-on:enlarge-text="onEnlargeText" ></blog-post> </div> </div> new Vue({ el: '#blog-posts-events-demo', data: { posts: [/* ... */], postFontSize: 1 //親側でpostFontSizeを宣言 }, methods:{ onEnlargeText: function (enlargeAmount) { this.postFontSize += enlargeAmount } } }) //============================
  9. コンポネントにV-modelでバインド <input v-model="searchText"> と <input v-bind:value="value"      v-on:input="$emit('input', $event.target.value)"    > 一致。 <custom-input v-bind:value="searchText" v-on:input="searchText = $event" ></custom-input> Vue.component('custom-input', { props: ['value'], template: ` <input v-bind:value="value"      v-on:input="$emit('input', $event.target.value)"    > ` })
  10. slot.予め確保した場所 <alert-box>//一旦以下のメッセージを表示させるが、具体的な表現は後で Something bad happened. </alert-box> Vue.component('alert-box', { template: ` <div class="demo-alert-box"> <strong>Error!</strong>//後で追加した表現内容です。 <slot></slot>      //ここは予め確保した場所です。 </div> ` })

ITIL4 Foundation Study Guide 2 : 4 Dimensions and 6 Factors

4  Dimensions:  Dimension1: Organizations & People Dimension2: Information & Technology Dimension3: Partners & Suppliers D...