前言
最近遇到一个项目,是对element-ui进行了二次封装,做了一些自己的组件库,其中很多实现都是render函数配合template模板实现的,还有就是表单这块是一块比较复杂的业务逻辑,里面用到了jsx语法,我也抽时间研究了jsx在vue中怎么使用,所以记录下自己写的demo,后面好进行查漏补缺。
主要内容
demo的主要结构如下
- Hello.vue
# Hello.vue
<script>
export default {
name: "Hello",
data() {
return {
str: "hello组件",
};
},
props: {
address: {
type: String,
default() {
return "这是地址";
},
},
},
render() {
return (
<div>
<span>{this.str}</span>
<h1>具名插槽</h1>
{/* 相当于声明了一个test的具名插槽 */}
{this.$slots.test}
<h1>作用域插槽</h1>
{/* 相当于声明了一个person的具名插槽,并传值,即作用域插槽 */}
{this.$scopedSlots.person({ name: 'john', age: 65 })}
</div>
);
},
};
</script>
<style scoped></style>
复制代码
- world.js
# world.js
export default {
data() {
return {
msg: "world组件",
detail: {
address: "杭州",
salary: "10k",
},
};
},
/* eslint-disable */
render() {
return (
<div>
<div>{this.msg}</div>
<div>{this.$slots.demo}</div>
<div>{this.$scopedSlots.data(this.detail)}</div>
</div>
);
},
};
复制代码
- demo.js
# demo.js
export default {
props: {
value: {
type: Object,
default() {
return {};
},
},
},
data() {
return {
msg: "demo2",
};
},
render() {
const { msg, value } = this;
return (
<div>
<input type="text" v-model={msg} />
<input type="text" v-model={value.name} />
<input type="text" v-model={value.address} />
</div>
);
},
};
复制代码
- App.vue
<!--<template>
<div id="app">
<div>{{ myProp }}</div>
<slot>默认插槽</slot>
<slot name="otherSlot" v-bind:msg="msg">其他插槽</slot>
<div ref="hahaha" v-if="isShow">{{ msg }}</div>
<div>
<button @click="change">点击</button>
</div>
<Hello>
<template v-slot:test>
<div>插槽</div>
<div>插槽</div>
</template>
<template v-slot:person="{ name, age }">
我叫{{ name }},今年{{ age }}岁
</template>
</Hello>
<world>
<template v-slot:demo> 这是world中的demo </template>
<template v-slot:data="detail">
{{ detail.address }}
{{ detail.salary }}
</template>
</world>
</div>
</template>-->
<script>
import Hello from "./components/Hello";
import World from "./components/world";
import Demo from "./components/demo";
export default {
name: "App",
components: { Hello, World, Demo },
props: {
myProp: {
type: String,
},
},
data() {
return {
isShow: false,
msg: "what this is",
$str: "这是以$符开头的key",
demo2: {
name: "demo",
address: "demo2 address",
},
};
},
created() {},
methods: {
test() {
console.log("this is test method");
},
change() {
this.isShow = true;
this.msg = "值被我改变了";
},
},
render() {
const { msg, isShow, demo2 } = this;
return (
<div id="app">
<div>{msg}</div> <br />
<slot>默认插槽</slot>
<slot name="otherSlot" msg={msg}>
其他插槽
</slot>
{/* jsx中没有v-if和v-for,但是可以通过三元表达式和map实现,具体可以看vue文档 */}
{isShow ? <div>{msg}</div> : <div>show false</div>}
<div>
{/* 如果没有从this中结构出来,就必须指定this */}
<button onClick={this.change}>点击</button>
</div>
{/* 子组件中如果声明了插槽,在jsx中必须这么使用 */}
<Hello
slots={{
test: () => {
return <div>test插槽</div>;
},
}}
scopedSlots={{
person: (props) => {
return (
<div>
我叫{props.name},今年{props.age}岁
</div>
);
},
}}
/>
<world
slots={{
demo: () => {
return <div>这是world中的demo</div>;
},
}}
// 这里也可以结构赋值使用,具体可以看vue文档
scopedSlots={{
data: ({ address, salary }) => {
return (
<div>
{address}
{salary}
</div>
);
},
}}
/>
{/* 测试v-mode双向绑定 */}
<demo v-model={demo2} />
</div>
);
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
复制代码
总结
注意点:
- render函数,如果render函数使用的不是ES6的语法,而是写key:value的形式,那么你就必须要写h变量,vue中指的就是createElement,或者你可以不写h变量,但是必须声明一个变量const h = this.$createElement,否则程序就会报错
- 如果使用了ES6的语法,就不要写h变量了,要写也可以,但是eslint校验会报错提示'h' is defined but never used,这时候只有禁用使用/* eslint disbale */来禁用eslinit校验了
例子:
代码语言:javascript复制# ES6
render() {
return (
<div>
<div>{this.msg}</div>
<div>{this.$slots.demo}</div>
<div>{this.$scopedSlots.data(this.detail)}</div>
</div>
);
},
# ES5
render: function(h) {
return (
<div>
<div>{this.msg}</div>
<div>{this.$slots.demo}</div>
<div>{this.$scopedSlots.data(this.detail)}</div>
</div>
);
},
# 或者
render: function() {
const h = this.$createElement
return (
<div>
<div>{this.msg}</div>
<div>{this.$slots.demo}</div>
<div>{this.$scopedSlots.data(this.detail)}</div>
</div>
);
},
复制代码
- jsx语法的话props传递就不要使用什么v-bind,直接使用key={variable},jsx语法中不管是传递值还是显示值都是一个花括号{},如果值是一个对象,形式就是{ {} },具体可以看vue文档和# babel-plugin-transform-vue-jsx文档
- 注意具名插槽和作用域插槽的使用