我说我是做外包的肯定没人信,给你看看外包程序员瞎几把搞的热情!
前排提醒:vue-jsx和react-jsx相差甚远,前者基本就是玩具生产链。很多想利用JS语言特性的骚套路基本上都不好实现,而且感觉奇奇怪怪的。所以你的生产环境,千万不要乱试vue-jsx这种搭配,够简单就无所谓了…
开局搭环境
要什么环境,vue-cli
就行了,又不是什么大项目大团队需要约定webpack
。
装插件
npm install\
babel-plugin-syntax-jsx\
babel-plugin-transform-vue-jsx\
babel-helper-vue-jsx-merge-props\
babel-preset-env\
--save-dev
.babelrc
主要是这个
{
"plugins": ["transform-vue-jsx"]
}
因为其他的东西基本上都会有,主要是要添加这个东西。至此。
正文
没错的这文章本来是属于实践的又不是教程。还是要讲一下自己的体验的。
渲染元素
感想最大的就是这个,Vue在使用jsx的时候很迷,最明显的感觉怪怪的地方有两个:
- 它并不是哪个位置的方法都会有createElement函数的。
- classes形式的组件找不到render函数!
其实关于vue与jsx,tsx我是做了很多次尝试
首先第一种,常规的就是一个object
对象,然后通过Vue.component()
方法构建。这种可以说是我现在看来最没坑的一种形式了。平常的话还是像*.vue
里的script
标签一样,直接export
打头开写,<template />
渲染部分移入了render()
函数。
export default {
render(/* h / createElement */) {
return <h1> Hello World </h1>
}
}
这种情况的结构与单文件的代码结构是相差无几的,不过换了种渲染方式而已,而且render()
函数可以做一些与渲染相关的子方法,比如条件渲染之类的。所以总的来说:
优点:
- 顺手,完全单文件中的
script
标签 - 没了
缺点:
- 这么搞肯定容易眼花啊!
- 不好维护,不直观
第二种,如果是这种结构的tsx的话,与jsx同理。
第三种,class形式的组件,需要vue-class-component
插件。然后可以写出类似于这样的东西
<template>
<h1>Hello World</h1>
</template>
<script>
@Component
export default class MainClass extends Vue {
}
</script>
乍一看你还以为这是Angular
呢!Vue在这方面真的是取长补短的典范。对这种的话,就比传统的方式要好多了,首先全局变量或者data()
函数返回值变得特别清晰;再者是原来methods
存放的函数可以以class
形式的函数来写,那computeds
怎么办?直接用get/set
关键词,太方便了有没有!
好了关键的来了…
@Component
export default class MainClass extends Vue {
get render() {
return <h1> Hello World </h1>
}
}
// render or template not defind.
这是什么鬼,可能是我操作不当,但是不加get
的话不会注入createElement,但是这又是个render()
函数,本来不需要加什么前缀的。但是不加有感觉会不会把render()
函数识别成是传统写法中存在于methods
的函数。
官方在自动注入这方面有一个栗子的
Vue.component('jsx-example', {
render () { // h will be injected
return <div id="foo">bar</div>
},
myMethod: function () { // h will not be injected
return <div id="foo">bar</div>
},
someOtherMethod: () => { // h will not be injected
return <div id="foo">bar</div>
}
})
@Component
class App extends Vue {
get computed () { // h will be injected
return <div id="foo">bar</div>
}
}
其中h
就是createElement
的别称,而且在jsx的话一般都是不用写的。所以这个函数注入的就有点迷了,不过根据亲测,在methods
定义的函数是有h
的,可能最后也会在render
函数里调用吧。
后来我尝试两三个星期之后,我就放弃了classes形式的jsx写法,等过几天又有经历的时候再继续尝试。目前自己在用的两套写法:例如Hyper
那种的classes形式的vue+ts,传统方式的jsx。
还有就是,对于vue来说,有时候要时常关心h
函数有没有被注入,这是一件挺不愉快的事情的。比如说你写了一个渲染函数,然后运行的时候发现惨了凉了函数刚好在渲染范围之外(比如把函数直接分离出去,并不存在于render
函数中),这是不运行的,那怎么做?
function example(h, args) {}
就是这样的!必须在render函数中调用而且h
必须是第一个参数!不然不是报错就是不渲染!
函数式组件
可能是解决刚刚提到的“经常找不到自动注入函数”的困扰吧。多了一个这么个东西。
export default {
functional: true,
render() {}
}
一个关键词functional
声明这个位置是个函数式组件。函数式可以直接看做一个能主动注入h
的函数,因为它没有状态的,甚至是个RBQ,用完就丢(死无全尸,在组件树是看不到的,依托父组件生存)。同时最大的特点也就是可复用。想想react
一个正常语法函数就能搞定的事情…
有利有弊,这种组件因为没状态,用过就丢,所以它需要的数据全靠传递。也就是单向数据,从父组件 -> props -> 处理 -> 输出 -> 销毁一条龙。很简单就是把它看做是render
里面的一个函数就行,本意也是如此。
所以这种组件就两个接收参数:负责渲染的h
,负责上下文context
。各种所需的乱七八糟都在context
中,比如全程最重要的props
。而且多数组件的参数都有调整:
props
:提供 props 的对象children
: VNode 子节点的数组slots
: slots 对象data
:传递给组件的 data 对象parent
:对父组件的引用listeners
: (2.3.0+) 一个包含了组件上所注册的v-on
侦听器的对象。这只是一个指向data.on
的别名。injections
: (2.3.0+) 如果使用了inject
选项,则该对象包含了应当被注入的属性。
JSX的一些小区别
因为我还没怎么体验过react
,所以就只有一个关于dom书写的区别。在react-jsx
中,class
可是会被识别成关键词的,所以做样式的class
要写成className
,但在vue-jsx
是不需要的。可能一开始这么做没想过后面竟然还有class-component
的需求吧。
vue
现在大多奇技淫巧都是基于社区的各种babel
插件,并不像react
两个官方库皇帝级别支持,也不像angular
自从诞生时期就声明“劳资要用TypeScript作为开发语言,你不用也得用ES6形式!”
vue-jsx
这种写法我现在也会用,搞点小的就直接这么写,而且这么做实际上思路会清晰一点——像在写一个应用而不是写一个网页,你只需要把dom相关的字段脑里想成一个字符串或者一个子函数就行了。(只是老遇到一些乱七八糟的问题)
(angular
与angular.js
至今还是两种东西,不要乱了)