Open Marinerer opened 2 years ago
JSX本质上是createElement
的语法糖,最终会被编译器转为createElement
函数。当在jsx
的标签中使用{ ...obj }
时, obj将会编译为createElement
的第二个参数([参见#Vue Data Object](#Vue Data Object))。
当不知道某个
vue
语法怎么用jsx
实现时,可以先转换为createElement
的data
对象,然后使用{...data}
写在jsx
标签上。在以 ES2015 语法声明的含有 JSX 的任何方法和 getter 中 (不是函数或箭头函数中) 自动注入
const h = this.$createElement
,这样就可以去掉(h)
参数了。
参考:
Via. https://github.com/vuejs/jsx
render() {
return <p>hello</p>
}
with dynamic content:
render() {
return <p>hello { this.message }</p>
}
when self-closing:
render() {
return <input />
}
with a component:
import MyComponent from './my-component'
export default {
render() {
return <MyComponent>hello</MyComponent>
},
}
注:
空标签
在React中可以使用空标签<></>
来实现包裹元素,在Vue中使用<template/>
是无效的,可以通过遍历来或者将组件放在一个Array内即可。比如<Layout>{ [<Sidebar />, <MainContent/>] }</Layout>
render() {
return <input type="email" />
}
with a dynamic binding:
render() {
return <input
type="email"
placeholder={this.placeholderText}
/>
}
with the spread operator (object needs to be compatible with Vue Data Object):
render() {
const inputAttrs = {
type: 'email',
placeholder: 'Enter your email'
}
return <input {...{ attrs: inputAttrs }} />
}
this.$slots
访问静态插槽的内容,每个插槽都是一个 VNode 数组;this.$scopedSlots
访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数。// slots
render() {
return (<div>{this.$slots.default}</div>)
}
// scoped slots
render() {
return (<div>{this.$slots.default({ name: 'John' })}</div>)
}
render() {
return (
<MyComponent>
<header slot="header">header</header>
<footer slot="footer">footer</footer>
</MyComponent>
)
}
render() {
const scopedSlots = {
header: () => <header>header</header>,
footer: () => <footer>footer</footer>
}
return <MyComponent scopedSlots={scopedSlots} />
}
<input vModel={this.newTodoText} />
with a modifier:
<input vModel_trim={this.newTodoText} />
// or
<el-input
value={this.inputValue}
on-input={val => this.inputValue = val.trim()}
/>
// domPropsInnerText 代替 v-text
<div domPropsInnerText={this.content}></div>
// domPropsInnerHTML 代替 v-html
<p domPropsInnerHTML={html} />
实际上,对于
domProps
,只有innerHTML
才需要使用domPropsInnerHTML
的写法,其他使用正常写法即可。
模板中使用的 v-if
和 v-for
,在渲染函数中用 if
/else
和 map
来重写。
事件处理都采用了箭头函数, 跟
react
一样, 需要处理this
绑定问题,可以使用bind
绑定。
v-on:事件名
绑定事件,jsx
中官方提供 vOn
进行绑定,修饰符通过下划线 split('_')
分割获得。<input vOn:click={this.newTodoText} />
<input vOn:click_stop_prevent={this.newTodoText} />
on + 事件名称
的大驼峰写法来监听,比如事件icon-click
,在JSX中写为onIconClick
- 监听原生事件的规则与普通事件是一样的,只需要将前面的
on
替换为nativeOn
- 这种监听事件的方式,事件修饰符只能通过代码去实现。
@click
=> onClick
@mouseover
=> onMouseenter
@click.native
=> nativeOnClick
data写法
const data = {
on: { click: this.clickHandler },
nativeOn: { mouseenter: this.mouseenterHandler }
}
render() {
return (
<MyComponent { ...data }></MyComponent>
)
}
事件修饰符:
.stop
: 阻止事件冒泡,event.stopPropagation()
.prevent
: 阻止默认行为, event.preventDefault()
.self
: 事件从绑定元素本身触发,if(event.target !== event.currentTarget) return
修饰符参见:https://vuejs.org/v2/guide/render-function.html#Event-amp-Key-Modifiers
高阶组件中的 v-on="$listeners"
和 v-bind="$attrs"
可以参照 data写法
, jsx
实现为:
const data = {
attrs: this.$attrs,
on: {
...this.$listeners,
click() {},
}
}
<button { ...data }><button>
自定义指令在JSX
里可以通过 directives
使用,比如 element-ui
的 v-loading
指令可以这样用:
在模板里:
<template>
<div v-loading.fullscreen.lock = "loading">...</div>
</template>
JSX
里:
render() {
/**
* modifiers指定修饰符,如果使用某一个修饰符,则指定这个修饰符的值为 true
* 不使用可以设置为false或者直接删掉
*/
const directives = [
{
name: 'loading',
value: this.loading,
modifiers: { fullscreen: true, lock: false }
}
]
return (
<div {
...{ directives }
}>加载内容</div>
)
}
Transpiles arrow functions that return JSX into functional components, when they are either default exports:
export default ({ props }) => <p>hello {props.message}</p>
or PascalCase variable declarations:
const HelloWorld = ({ props }) => <p>hello {props.message}</p>
Via. https://cn.vuejs.org/v2/guide/render-function.html
{
// 与 `v-bind:class` 的 API 相同,
// 接受一个字符串、对象或字符串和对象组成的数组
'class': {
foo: true,
bar: false
},
// 与 `v-bind:style` 的 API 相同,
// 接受一个字符串、对象,或对象组成的数组
style: {
color: 'red',
fontSize: '14px'
},
// 普通的 HTML attribute
attrs: {
id: 'foo'
},
// 组件 prop
props: {
myProp: 'bar'
},
// DOM property
domProps: {
innerHTML: 'baz'
},
// 事件监听器在 `on` 内,
// 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
// 需要在处理函数中手动检查 keyCode。
on: {
click: this.clickHandler
},
// 仅用于组件,用于监听原生事件,而不是组件内部使用
// `vm.$emit` 触发的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
// 赋值,因为 Vue 已经自动为你进行了同步。
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// 作用域插槽的格式为
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果组件是其它组件的子组件,需为插槽指定名称
slot: 'name-of-slot',
// 其它特殊顶层 property
key: 'myKey',
ref: 'myRef',
// 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
// 那么 `$refs.myRef` 会变成一个数组。
refInFor: true
}
Via. https://cn.vuejs.org/v2/guide/render-function.html
函数式组件
是一个只接受 prop 的函数。它无状态的 (没有响应式数据),也没有实例 (没有 this
上下文,也没有生命周期方法)。
Vue.component('my-component', {
functional: true,
// Props 是可选的
props: {
// ...
},
// 为了弥补缺少的实例
// 提供第二个参数作为上下文
render: function (createElement, context) {
// ...
}
})
组件需要的一切都是通过 context
参数传递,它是一个包括如下字段的对象:
props
:提供所有 prop 的对象children
:VNode 子节点的数组slots
:一个函数,返回了包含所有插槽的对象scopedSlots
:(2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽。data
:传递给组件的整个数据对象,作为 createElement
的第二个参数传入组件parent
:对父组件的引用listeners
:(2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是 data.on
的一个别名。injections
:(2.3.0+) 如果使用了 inject
选项,则该对象包含了应当被注入的 property。createElement
函数返回的值称之为虚拟节点,即VNode
,而由VNode
组成的树便是虚拟DOM
。
VNode
必须唯一
React JSX