やっとvueのrender関数(二)がわかった(笑・̀ㅂ•́)و✧
29280 ワード
文書ディレクトリまずvm.$を理解してください.scopedSlots データオブジェクト に深く入り込む JSX
注意:このコードは、単一ファイルコンポーネントで作成されます.コードアドレス
まずvm.$を調べてみましょうscopedSlots
役割ドメインスロットにアクセスできます.
注:2.6.0から、このpropertyには2つの変化があります.役割ドメインスロット関数は、戻り値が無効な場合に のすべての
つまり、
⚠️ コードを修正する前に
前章のは
データ・オブジェクトの詳細
表では、操作ボタンをレンダリングするときに使用されることが多いので、直接見てみましょう.
JSX
render関数は私たちの問題を解決しましたが、本当に面倒です.
これは、VueでJSX構文を使用するためのBabelプラグインがあり、テンプレートに近い構文に戻ることができます.
JSXの使用:インストールプラグイン を追加します.
ここで、上記のコンポーネントをJSXの書き方に変更します.
次のように書くこともできます.
⚠️
注意:このコードは、単一ファイルコンポーネントで作成されます.コードアドレス
まずvm.$を調べてみましょうscopedSlots
vm.$scopedSlots
役割ドメインスロットにアクセスできます.
slot
を含む各スロットについて、オブジェクトは対応するVNodeを返す関数を含む.注:2.6.0から、このpropertyには2つの変化があります.
undefined
を返さない限り、VNode配列を返すことを保証します.$slots
は、$scopedSlots
に関数として露出するようになった.レンダー関数を使用している場合は、現在のスロットにスコープがあるかどうかにかかわらず、$scopedSlots
から常にアクセスすることをお勧めします.これにより、将来の役割ドメインの追加が簡単になるだけでなく、すべてのスロットが関数であるVue 3に最終的に簡単に移行することができます.つまり、
$scopedSlots
ですべてのスロットにアクセスできるが、$slots
は直接VNodeに戻り、$scopedSlots
はVNode関数(関数の戻り値はVNode)を返す.⚠️ コードを修正する前に
vue
を2.6.0にアップグレードしてから、vue-template-compiler
バージョンもvue
バージョンと一致しなければなりません.もしあなたのプロジェクトがこの間違いError: [vue-loader] vue-template-compiler must be installed as a peer depend
を報告したら、それはその2つのバージョンが一致していないためです.アップグレードコマンド:npm update vue vue-template-compiler
前章のは
header
とdefault
をそれぞれに変更するだけです.- let _header = _this.$slots.header
+ let _header = _this.$scopedSlots.header()
- _this.$slots.default
+ _this.$scopedSlots.default()
データ・オブジェクトの詳細
表では、操作ボタンをレンダリングするときに使用されることが多いので、直接見てみましょう.
// BaseButton.vue
<template>
<div class="button-card">
<div>
<slot name="title"></slot>
</div>
<button :class="[`${type}`, `${size}`]" @click="handleClick">
<slot name="button" v-bind:children="contentObj">{{ contentObj.text }}</slot>
</button>
<p>
<slot>help</slot>
</p>
</div>
</template>
<script>
export default {
name: 'BaseButton',
props: {
type: {
type: String,
default: ''
},
size: {
type: String,
default: ''
},
contentObj: {
type: Object,
default() {
return {}
}
}
},
methods: {
handleClick() {
this.$emit('click')
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.button-card {
background: #eee;
border-radius: 8px;
padding: 24px;
}
button {
border-radius: 4px;
}
.success {
background-color: rgb(149, 204, 149);
border: 1px solid rgb(149, 204, 149);
color: #fff;
}
.warning {
background-color: orange;
border: 1px solid orange;
color: #fff;
}
.danger {
background-color: red;
border: 1px solid red;
color: #fff;
}
.small {
height: 20px;
padding: 0 8px;
}
.middle {
height: 32px;
padding: 0 12px;
}
.large {
height: 40px;
padding: 0 20px;
}
</style>
//
// 1.
import BaseButton from './BaseButton'
// 2. render
renderButton: {
render: function(createElement) {
const _this = this['$options'].parent
return createElement(BaseButton, {
// `v-bind:class` API , 、
class: {
'base-button': true,
'ui-button': false
},
// `v-bind:style` API , 、 ,
style: {
// color: 'red',
fontSize: '14px'
},
// HTML attribute, BaseButton
attrs: {
id: 'base-button'
},
// prop, props
props: {
type: 'warning',
size: 'large',
contentObj: {
text: 'Confirm',
icon: '❓'
}
},
// DOM property, , `innerHTML`
// domProps: {
// innerHTML: 'button , '
// },
// `on` ,
// `v-on:keyup.enter` 。
// keyCode。
// `$emit` ,
on: {
click: _this.clickHandler,
dblclick: _this.dblclickHandler
},
// , , `vm.$emit` 。
nativeOn: {
dblclick: _this.nativeClickHandler
},
// 。
// directives: [],
// :{ name: props => VNode | Array }
scopedSlots: {
default: props => {
if (props.children) {
return createElement('span', props.children.text + ' ?')
}
return createElement('span', 'parent slot defult')
}
},
// , 。
slot: 'name-of-slot'
// property。
// key: '',
// ref: '',
// refInFor: true
})
}
},
// 3. `renderButton`
<renderButton />
JSX
render関数は私たちの問題を解決しましたが、本当に面倒です.
これは、VueでJSX構文を使用するためのBabelプラグインがあり、テンプレートに近い構文に戻ることができます.
JSXの使用:
npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
.babelrc
ファイルを新規作成し(プロジェクトにない場合)、次の構成{
"presets": ["@vue/babel-preset-jsx"]
}
ここで、上記のコンポーネントをJSXの書き方に変更します.
renderButtonWidthJSX: {
render(h) {
const _this = this['$options'].parent
const contentObj = { text: 'jsx' }
return (
<BaseButton
type="danger"
size="small"
contentObj={contentObj}
style={{ fontSize: '12px' }}
class="jsx-button"
onclick={_this.clickHandler}
scopedSlots={{
title: () => <h1>jsx title</h1>,
// button: () => 'Delete',
default: () => <span>default</span>
}}
/>
)
}
}
次のように書くこともできます.
renderButtonWidthJSX: {
render(h) {
const _this = this['$options'].parent
const contentObj = { text: 'jsx' }
return (
<BaseButton
{...{
props: {
type: 'danger',
size: 'small',
contentObj,
style: { fontSize: '12px' },
class: 'jsx-button'
},
on: {
click: _this.clickHandler,
dblclick: _this.dblclickHandler
},
nativeOn: {
dblclick: _this.nativeClickHandler
},
scopedSlots: {
title: () => <h1>jsx title</h1>,
// button: () => 'Delete',
default: () => <span>default</span>
}
}}
/>
)
}
}
⚠️
render
関数はh
パラメータを使用していませんが、送信する必要があります.そうしないと、エラーが発生します.h
をcreateElement
の別名とすることはVue生態系における一般的な慣例であり,実際にはJSXが要求している.VueのBabelプラグインの3.4.0バージョンから、ES 2015構文で宣言されたJSXを含む任意の方法とgetter(関数や矢印関数ではない)にconst h = this.$createElement
を自動的に注入し、(h)
パラメータを削除することができます.以前のバージョンのプラグインでは、h
が現在の役割ドメインで使用できない場合、アプリケーションは間違っています.