Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSX #44

Open
Meqn opened this issue Dec 26, 2021 · 2 comments
Open

JSX #44

Meqn opened this issue Dec 26, 2021 · 2 comments

Comments

@Meqn
Copy link
Owner

Meqn commented Dec 26, 2021

No description provided.

@Meqn
Copy link
Owner Author

Meqn commented Dec 26, 2021

React JSX

@Meqn
Copy link
Owner Author

Meqn commented Dec 26, 2021

Vue JSX

JSX本质上是createElement的语法糖,最终会被编译器转为createElement函数。当在jsx的标签中使用{ ...obj }时, obj将会编译为createElement的第二个参数([参见#Vue Data Object](#Vue Data Object))。

  1. 当不知道某个vue语法怎么用jsx实现时,可以先转换为createElementdata对象,然后使用{...data}写在jsx标签上。

  2. 在以 ES2015 语法声明的含有 JSX 的任何方法和 getter 中 (不是函数或箭头函数中) 自动注入 const h = this.$createElement,这样就可以去掉 (h) 参数了。

参考:

Syntax

Via. https://github.com/vuejs/jsx

Content

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>
  },
}

注:

  1. 空标签 在React中可以使用空标签<></>来实现包裹元素,在Vue中使用<template/>是无效的,可以通过遍历来或者将组件放在一个Array内即可。比如 <Layout>{ [<Sidebar />, <MainContent/>] }</Layout>

Attributes/Props

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 }} />
}

Slots

  1. 通过 this.$slots 访问静态插槽的内容,每个插槽都是一个 VNode 数组;
  2. 通过 this.$scopedSlots 访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数。
// slots
render() {
  return (<div>{this.$slots.default}</div>)
}

// scoped slots
render() {
  return (<div>{this.$slots.default({ name: 'John' })}</div>)
}
  1. named slots:
render() {
  return (
    <MyComponent>
      <header slot="header">header</header>
      <footer slot="footer">footer</footer>
    </MyComponent>
  )
}
  1. scoped slots:
render() {
  const scopedSlots = {
    header: () => <header>header</header>,
    footer: () => <footer>footer</footer>
  }
  return <MyComponent scopedSlots={scopedSlots} />
}

Directives

v-model

<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()}
 />

v-text 和 v-html

// domPropsInnerText 代替 v-text
<div domPropsInnerText={this.content}></div>

// domPropsInnerHTML 代替 v-html
<p domPropsInnerHTML={html} />

实际上,对于domProps,只有innerHTML才需要使用domPropsInnerHTML的写法,其他使用正常写法即可。

v-if 和 v-for

模板中使用的 v-ifv-for ,在渲染函数中用 if/elsemap 来重写。

Event & Key Modifiers

事件处理都采用了箭头函数, 跟react一样, 需要处理this绑定问题,可以使用bind绑定。

  1. 模板中通过 v-on:事件名 绑定事件,jsx 中官方提供 vOn 进行绑定,修饰符通过下划线 split('_') 分割获得。
<input vOn:click={this.newTodoText} />
<input vOn:click_stop_prevent={this.newTodoText} />
  1. JSX中,也可以通过on + 事件名称的大驼峰写法来监听,比如事件icon-click ,在JSX中写为onIconClick
  1. 监听原生事件的规则与普通事件是一样的,只需要将前面的on 替换为 nativeOn
  2. 这种监听事件的方式,事件修饰符只能通过代码去实现。
  • @click => onClick
  • @mouseover => onMouseenter
  • @click.native => nativeOnClick
  1. 参照 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-uiv-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>
	)
}

Functional Components

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>

Vue Data Object

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
}

Functional Components

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。

VNode

createElement 函数返回的值称之为虚拟节点,即VNode,而由VNode组成的树便是虚拟DOM

VNode 必须唯一

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant