一、组件入门
涉及到的知识点主要是Vue.extend()、$mount、$el.
1. Vue.extend
使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
需要创建实例挂载。如果想挂载在body上,怎样写呢?
document.body.appendChild(new Profile.$mount().$el);
2. $mount
Vue实例还没有收到el选项,处于未挂载状态,可以使用vm.$mount()手动挂载一个未挂载的实例。如果没有传参,通过$el获根部取DOM元素,必须使用DOM api插入文档中。
3. new Vue()
也可以通过新建vue实例append到body中
const vm = new Vue({
render(h) {
// render方法提供给我们一个h函数,它可以渲染VNode
return h(Component, {props})
}
}).$mount();
document.body.appendChild(vm.$el);
二、Tree组件
Tree组件最适合的结构是无序列表ul,创建一个递归组件Item表示Tree选项,如果当前Item存在children,则递归渲染子树,以此类推;同时添加一个标识管理当前层级item的展开状态。
具体实现
tree.vue遍历第一级导航,v-bind传递数据。
<template>
<div>
<div v-for="(treeList,key) in treeData" :key="key">
<treeItem :treeData="treeList"></treeItem>
</div>
</div>
</template>
<script>
import treeItem from './treeItem'
export default {
name:'tree',
components:{treeItem},
data(){
return {
treeData: [
{
title: "菜单1",
children: [
{
title: "Java架构师"
},
{
title: "JS高级",
children: [
{
title: "ES6"
},
{
title: "动效"
}
]
},
{
title: "Web全栈",
children: [
{
title: "Vue训练营",
expand: true,
children: [
{
title: "组件化"
},
{
title: "源码"
},
{
title: "docker部署"
}
]
},
{
title: "React",
children: [
{
title: "JSX"
},
{
title: "虚拟DOM"
}
]
},
{
title: "Node"
}
]
}
]
},
{
title: "菜单2",
children: [
{
title: "Java架构师"
},
{
title: "JS高级",
children: [
{
title: "ES6"
},
{
title: "动效"
}
]
},
{
title: "Web全栈",
children: [
{
title: "Vue训练营",
expand: true,
children: [
{
title: "组件化"
},
{
title: "源码"
},
{
title: "docker部署"
}
]
},
{
title: "React",
children: [
{
title: "JSX"
},
{
title: "虚拟DOM"
}
]
},
{
title: "Node"
}
]
}
]
}
]
}
}
}
</script>
treeItem接收父组件传来的数据,如果有children,则循环递归,并通过v-bind传入数据。 isOpen对应不同的treeItem组件
<template>
<div>
<li>
<div>
{{treeData.title}}
<span v-if="isfolder" class="btn" @click="toggle">{{isopen?'-':'+'}}</span>
</div>
<div v-if="isfolder&&isopen">
<treeItem v-for="(item,key) in treeData.children" :treeData = item :key="key"></treeItem>
</div>
</li>
</div>
</template>
<script>
export default {
name:'treeItem',
props:['treeData'],
data(){
return {
isopen:false
}
},
computed:{
isfolder(){
return this.treeData.children && this.treeData.children.length;
}
},
methods:{
toggle(){
this.isopen = !this.isopen;
}
}
}
</script>
<style scoped>
*{text-align: left}
li{list-style: none;padding-left: 20px;}
.btn{cursor: pointer;font-size: 20px;}
</style>>
三、弹窗组件
1. create函数
create函数⽤于动态创建指定组件实例并挂载⾄body
import Vue from "vue";
// 创建函数接收要创建组件定义
function create(Component, props) {
// 创建⼀个Vue新实例
const vm = new Vue({
render(h) {
// render函数将传⼊组件配置对象转换为虚拟dom
console.log(h(Component, { props }));
return h(Component, { props });
},
}).$mount(); //执⾏挂载函数,但未指定挂载⽬标,表示只执⾏初始化⼯作
// 将⽣成dom元素追加⾄body
document.body.appendChild(vm.$el);
// 给组件实例添加销毁⽅法
const comp = vm.$children[0];
comp.remove = () => {
document.body.removeChild(vm.$el);
vm.$destroy();
};
return comp;
}
// 暴露调⽤接⼝
export default create;
2. 组件代码
notice.vue
<template>
<div class="box" v-if="isShow">
<h3>{{title}}</h3>
<p class="box-content">{{message}}</p>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
message: {
type: String,
default: "",
},
duration: {
type: Number,
default: 1000,
},
},
data() {
return {
isShow: false,
};
},
methods: {
show() {
this.isShow = true;
setTimeout(this.hide, this.duration);
},
hide() {
this.isShow = false;
this.remove();
},
},
};
</script>
<style>
.box {
position: fixed;
width: 100%;
top: 16px;
left: 0;
text-align: center;
pointer-events: none;
}
.box-content {
width: 200px;
margin: 10px auto;
font-size: 14px;
border: blue 3px solid;
padding: 8px 16px;
background: #fff;
border-radius: 3px;
margin-bottom: 8px;
}
</style>
3.调用组件
<script>
import create from "@/utils/create";
import Notice from "@/components/Notice";
export default {
methods: {
submitForm(form) {
this.$refs[form].validate(valid => {
const notice = create(Notice, {
title: "社会你杨哥喊你来搬砖",
message: valid ? "请求登录!" : "校验失败!",
duration: 1000
});
notice.show();
});
}
}
};
</script>