Tree、弹窗组件

214 阅读1分钟

一、组件入门

涉及到的知识点主要是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>