源码在 https://github.com/xiaodun/sf-feed
函数式组件
<TagConvert tag="span" age="9" sex="man">12312</TagConvert>
生成的DOM如下
<span age="9" sex="man">12312</span>
内部实现是这样的,用到自定义组件上,意义就大了
<script>
export default {
functional: true,
name: "TagConvert_vue",
props: {
tag: {
type: String,
default: "div"
}
},
render(createElement, context) {
return createElement(context.props.tag, context.data, context.children);
}
};
</script>
v-bind="$attrs"
批量绑定父组件传递过来的属性
看一下iview官网上,表单验证的模板代码
handleSubmit(name) {
this.$refs[name].validate((valid) => {
if (valid) {
this.$Message.success('Success!');
} else {
this.$Message.error('Fail!');
}
})
}
name 对应的是<Form ref="formInline">
现在我想封装一个专门用来提交的<Submit>
组件,只有在验证成功的时候触发回调
<Submit @submit="onSubmit">
<Button
width="100%"
:status="submitStatus"
class="login-btn"
height="36px"
>{{$t('login')}}</Button>
</Submit>
上述这样会多一层无用的DOM嵌套,我希望是这样的
<Submit
width="100%"
:status="submitStatus"
class="login-btn"
height="36px"
@submit="onSubmit"
>{{$t('login')}}</Submit>
<Submit>
内部实现结合了<TagConvert>
和v-bind="$attrs"
<template>
<TagConvert
v-if="tag[0].charCodeAt(0)<=90"
:tag="tag"
v-bind="$attrs"
@click.native="onSubmit"
>
<slot></slot>
</TagConvert>
<!-- 原生组件 -->
<TagConvert
v-else
:tag="tag"
v-bind="$attrs"
@click="onSubmit"
>
<slot></slot>
</TagConvert>
</template>
<script>
import { findParentComponent } from "../../find";
export default {
name: "Submit_vue",
props: {
tag: {
type: String,
default: "Button"
}
},
methods: {
onSubmit($event) {
$event.preventDefault();
//查找
let validInfo = this.submitComponent.onValidator();
if (validInfo.status) {
this.$emit("submit", validInfo.passValues);
}
}
},
mounted() {
let findInfo = findParentComponent(this, "FormItem");
if (!findInfo.status) {
findInfo = findParentComponent(this, "Form");
}
if (findInfo.status) {
this.submitComponent = findInfo.component;
} else {
console.error("没有找到Form或FormItem");
}
}
};
</script>
findParentComponent
是基于Vue自身节点构造,可以通过$parent
追溯父元素,$children
遍历子元素
provide 与 inject
这种适合<Form>
和 <FormItem>
这种父子组件
在<Form>
中
export default {
name: "Form_vue",
props: {
labelWidth: String
},
provide() {
return {
Form: this
};
}
}
在<FormItem>
中
export default {
name: "FormItem_vue",
inject: ["Form"],
}
<FormItem>
可以 this.Form
访问
如果<FormItem>
没有得到<Form>
的引用会报错哦
动态挂载HTML
render
的动态再需要通过JS触发时,是乏力的,比如一个类似于iview 的<Notice>
组件,需要如下手段
import Notification from "./Notification";
import Vue from 'vue';
const NotificationInstance = (() => {
let instance = new Vue({
render(createElement) {
return createElement(Notification)
}
})
const component = instance.$mount();
document.body.appendChild(component.$el);
const notification = instance.$children[0];
return notification;
})();
Vue.prototype.$Notice = {
show(argOptions) {
NotificationInstance.add(argOptions);
}
}
可以this.$Notice.show
来触发
上述可发现,React可以做到的,Vue也可以做到,可有千秋。
但是Vue更贴近开发者和业务场景,React的抽象层次更高,具体的落实需要开发者去做,更适合研究琢磨,这么看来,React会走的更远。
人生苦短,我用Vue。