做者:JThtml
译者:前端小智前端
来源:scotch.io/vue
点赞再看,养成习惯node
本文
GitHub
github.com/qq449245884… 上已经收录,更多往期高赞文章的分类,也整理了不少个人文档,和教程资料。欢迎Star和完善,你们面试能够参照考点复习,但愿咱们一块儿有点东西。git
Vue.js 具备简单的 API 和几个选项,可用于在咱们的组件中定义HTML模板。github
咱们可使用<template>
标签选项,在根组件实例上定义template
属性,或者使用单文件组件。面试
上面的选项很棒而且能够完美地工做,可是,在您的应用程序的生命周期中,有时会感到笨拙,设计过分或很是不灵活。npm
那么,咱们为何要使用 JSX 而不是其余模板定义呢?编程
<div></div>
的写法一看就是比 this.$createElement('div', {}, [...])
简洁不少。先举一个例子来讲明为何 JSX 是好的。json
咱们要构建一个<TextField/>
组件,该组件能够是普通的单行文本输入或多行输入(文本区域)。 咱们的模板声明可能看起来像这样。
<div>
<textarea v-if="multiline" v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false">
<input v-else v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false">
</div>
复制代码
从上面的代码片断中能够看到,咱们很快就会遇到一些问题,好比重复代码等等。想象一下,必须支持input
上面所列的各类属性。上面的这个小片断将会增加并成为一个难以维护的噩梦。
要解决这个问题,咱们须要使用Vue进行降级处理,所以须要使用理接近Vue的内部API来解决这个问题。
注意:这里并非说没有JSX就没有一种简单的方法来处理上面的问题,只是说将这个逻辑移动到带有JSX的
render()
方法可使组件更直观。
咱们在 Vue 中建立的每一个组件都有一个render
方法。这个就是 Vue 选择渲染组件的地方。即便咱们不定义这个方法,Vue 也会为咱们作这件事。
这意味着当咱们在 Vue 中定义 HTML 模板时,Vue 的模板编译器将其编译为一个createElement
函数,该函数带有几个参数并从render
函数返回结果。
为了修复上一节中的代码,咱们删除了template
属性或template
标签,并在组件上定义了render()
方法。 若是在组件上定义了render
方法,则 Vue 将忽略template
定义。
...
export default {
name: 'TextField',
render (createElement) {
const tag = this.multiline ? 'textarea' : 'input'
return createElement(tag, {
class: {
'text-input': true,
'is-disabled': false
},
attrs: {
name: this.name,
placeholder: this.placeholder,
'aria-invalid': false
}
})
}
}
...
复制代码
上面的代码作了几件事:
render
方法从Vue获取一个createElement
助手。createElement
的选项不少。咱们为 Vue 组件定义的每一个模板都将转换为可返回createElement
函数的render
方法。 由于这个缘由,render
方法将优先于模板定义。
举个例子:
// HTML
<div>
<p>Only you can stop forest fires</p>
</div>
复制代码
模板编译器将把上面的 HTML 转换成:
...
render (createElement) {
return createElement(
'div',
{},
createElement(
'p',
{},
'Only you can stop forest fires'
)
)
}
...
复制代码
如今你可能会问这个问题:“对可读性来讲这很差吗?” 答案是确定的。 一旦定义了具备许多元素嵌套级别或具备多个同级元素的组件,咱们就会遇到这个新问题。
这就是 JSX 出现的缘由,它能够很好的解决此类问题。
JSX 是 Facebook 工程团队创造的一个术语。
JSX 是 JavaScript 的相似XML的语法扩展,没有任何定义的语义。
JSX 不打算由引擎或浏览器实现。相反,咱们将使用 Babel 之类的转置器将JSX转换成常规的 JS 。
// 此行是JSX的示例
const heading = <h1>Welcome to Scotch</h1>;
复制代码
基本上,JSX 容许咱们在 JS 中使用相似 Html 的语法。
若是使用的 Vue-cli 大于或等于 3.0 版本,那么就直接可使用JSX的语法了。
若是您使用的是不支持 JSX 的Vue-cli较旧版本,则能够经过安装babel-preset-vue-app
来添加它,并将其添加到您的.babelrc
文件中。
# Using npm
npm install --save-dev babel-preset-vue-app
# Using yarn
yarn add --dev babel-preset-vue-app
复制代码
在.babelrc
文件中,添加:
{
"presets": ["vue-app"]
}
复制代码
咱们如今能够在组件的render
函数中使用 JSX。
在 Vue 中使用JSX须要注意几点。
要监听 JSX 中的事件,咱们须要“on”
前缀。 例如,将onClick
用于单击事件。
render (createElement) {
return (
<button onClick={this.handleClick}></button>
)
}
复制代码
要修改事件,请使用
render (createElement) {
return (
<button onClick:prevent={this.handleClick}></button>
)
}
复制代码
绑定变量,注意这里不是使用 :
render (createElement) {
return (
<button content={this.generatedText}></button>
)
}
复制代码
将HTML字符串设置为元素的内容,使用domPropsInnerHTML
而不是使用v-html
render (createElement) {
return (
<button domPropsInnerHTML={htmlContent}></button>
)
}
复制代码
咱们也能够展开一个大对象:
render (createElement) {
return (
<button {...this.largeProps}></button>
)
}
复制代码
回到咱们最初的“TextField”
组件。如今咱们已经在 Vue 应用程序中启用了 JSX,咱们如今能够这样作了。
render (createElement) {
const inputAttributes = {
class: 'input-field has-outline', // class definition
onClick: this.handleClick // event handler
backdrop: false // custom prop
}
const inputMarkup = this.multiline
? <textarea {...inputAttributes}></textarea>
: <input {...inputAttributes}/>
return inputMarkup
}
复制代码
在 Vue 中使用JSX的另外一个好处是,咱们再也不须要注册所需的每一个组件。 咱们只是导入和使用。
import {Button} from '../components'
export default {
render (createElement) {
return <Button primary={true}>Edit</Button>
}
}
复制代码
TypeScript 用做一种向 JavaScript添加类型检查的机制。要在 JSX 支持 TypeScript中,须要修改 tsconfig.json
。
要在 TypeScript 中启用 JSX,请先将该文件另存为.tsx
文件,而后将tsconfig.json
修改成包括:
{
"compilerOptions": {
....
"jsx": "preserve",
}
}
复制代码
将jsx
选项设置为“preserve”
意味着 TypeScript 不该处理JSX。 这样作使 Babel 能够控制全部JSX 和 TypeScript 坚持使用类型,由于它尚不支持 Vue JSX。
而后在项目中建立一个jsx.d.ts
文件,并为 Vue 添加 TypeScript JSX 声明。
import Vue, {VNode} from 'vue'
declare global {
namespace JSX {
interface Element extends VNode {}
interface ElementClass extends Vue {}
interface ElementAttributesProperty {
$props: {}
}
interface IntrinsicElements {
[elemName: string]: any
}
}
}
复制代码
确保 TypeScript 能够加载声明文件。 或者,能够经过如下方式在tsconfig.json
中为其添加自动加载功能:
{
"compilerOptions": {
...
"typesRoot": ["./node_modules/@types", "./types"]
}
}
复制代码
代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug。
文章每周持续更新,能够微信搜索「 大迁世界 」第一时间阅读和催更(比博客早一到两篇哟),本文 GitHub github.com/qq449245884… 已经收录,整理了不少个人文档,欢迎Star和完善,你们面试能够参照考点复习,另外关注公众号,后台回复福利,便可看到福利,你懂的。