vue高级进阶( 三 ) 组件高级用法及最佳实践

世界上有太多孤独的人害怕先踏出第一步。 ---绿皮书

书接上回,上篇介绍了vue组件通信比较有代表性的几种方法,本篇主要讲述一下组件的高级用法和最佳实践,争取用最少的篇幅占领高地!(多说一句,后续这个系列会有vue最佳实践和源码解读,我总有办法能让大家看懂,所以点赞关注,不迷路啊,小老弟

本篇主要内容

  • 递归组件
  • 动态组件
  • 异步组件
  • 内联模板 inline-template的使用
  • 全局组件批量自动注册
  • Vue 的构造器——extend
  • vue 修饰符sync深入解析

正文开始

递归组件

函数的递归是自己调用自己,这个过程有两个必要条件:

  • 这个函数必须有函数名称
  • 这个递归函数必须有结束条件,不然就会报Maximum call stack size exceeded,内存溢出

本质上讲,组件也是一个函数,递归组件自然也是自己调用自己,所以也要满足两个条件:

  • 这个组件必须有确定的name,也就是要给组件设置name
  • 必须要有一个结束条件,告诉组件什么时候递归结束

上代码

非常简单的功能,让你看懂递归,A.vue中引入B.vue,B组件是递归的核心所在

<template>
// 要将treeData通过prop进行传递
<B :propTreeData="treeData"/>
</template>
<script>
import B from './B'
export default {
name: "Tree",
data() {
return {
treeData: [
{
id: "1",
menuName: "笑傲江湖",
menuCode: "1",
children: [
{
menuName: "令狐冲",
menuCode: "10"
},
{
menuName: "东方不败",
menuCode: "11"
}
]
},
{
id: "2",
menuName: "射雕英雄",
menuCode: "2",
children: [
{
menuName: "蓉儿",
menuCode: "20"
},
{
menuName: "郭靖",
menuCode: "21"
}
]
}
]
};
},
components:{B}
};
</script>

B组件,递归的核心,由于是递归,必须结构一致,因此就必须将A中的treeData通过Props传给B才能实现递归,这就是为啥A和B必须分离,而绝不可能通过一个组件来实现递归,不知道你懂了没?体会一下

<template>
<ul>
<li v-for="item in propTreeData" :key="item.menuCode">
{{item.menuName}}
// 要有一个结束条件
<tree v-if="item.children&&item.children.length" :propTreeData="item.children"></tree>
</li>
</ul>
</template>
<script>
export default {
name: "Tree",
props:{
propTreeData:Array,
default:()=>([])
},
};
</script>

看下实现效果,这是一个最最简单的递归,但是后续的所有的复杂功能,折叠,选中,拖拽哪一个又不是基于这个来进行的呢?复杂功能大家可以继续扩展,都不难

<figcaption style="box-sizing: border-box; outline: 0px; display: block; text-align: center; margin: 8px; color: rgb(153, 153, 153); font-size: 14px; overflow-wrap: break-word;"></figcaption>

动态组件

让多个组件使用同一个挂载点,并动态切换,这就是动态组件。

通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,可以实现动态组件

<template>
<div id="example">
<button @click="change">切换页面</button>
<component :is="currentView"></component>
</div>
</template> <script>
var LZL = { template: "<div>林志玲</div>" };
var GYY = { template: "<div>高圆圆</div>" };
var JJW = { template: "<div>贾静雯</div>" }; export default {
name: "App",
components: {
LZL,
GYY,
JJW
},
data() {
return {
index:0,
arr:['LZL','GYY','JJW'],
};
},
computed:{
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
this.index = (++this.index)%3;
}
}
};
</script>

动态组件的缓存,会将不活动的组件实例缓存起来,而不是销毁它们,比如切换tab后,还能保持切换之前的状态,如果有多个条件性的子元素,<keep-alive> 要求同时只有一个子元素被渲染

 <keep-alive>
<component :is="currentView"></component>
</keep-alive>
----------------------------------------------- <keep-alive>` 要求同时只有一个子元素被渲染 <keep-alive>
<LZL v-if="index===0"></LZL>
<GYY v-else-if="index===1"></GYY>
<JJW v-else></JJW>
</keep-alive>

使用的时候,比如keep-alive下有A,B,C三个组件,但是我只想缓存A和B,这时候该怎么办,就要用到include和exclude】来进行筛选过滤,根据你的过滤 条件确定缓存哪个组件

include会匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称(父组件 components 选项的键值)。匿名组件不能被匹配

<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正则表达式 (使用 v-bind) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- Array (use v-bind) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>

异步组件

异步组件说白了就是按需加载,使用时才装入需要的组件,可以有效的提高首次装入页面的速度。比如在路由切换时。

 {
path: '/promisedemo',
name: 'PromiseDemo',
component: resolve => require(['../components/PromiseDemo'], resolve)
}

利用此特性,我们便能做很多针对前端的优化。 比如:将页面核心功能(音、视频播放、文章、商品等等)打包成一个核心模块,通过框架优先加载。 其他的一些周边功能打包后,通过服务器异步加载,从而解决业务需求越来越多导致的系统难维护、访问慢问题。

既然是异步加载,就会存在加载过程(正在加载中)、以及加载失败等异常情况,看下图一目了然。。。

<figcaption style="box-sizing: border-box; outline: 0px; display: block; text-align: center; margin: 8px; color: rgb(153, 153, 153); font-size: 14px; overflow-wrap: break-word;"></figcaption>

内联模板 inline-template的使用

Vue提供了一种内联模板的功能,在使用组件时,给标签加上inline-complate特性,组件就会把它的内容当作模板,而不是当内容分发。其实也就是说,不在创建一个组件时定义它的模板,而是在声明的外部创建。

父组件
<child-component inline-template>
<div>
<h2>在父组件中定义子组件的模板</h2>
<p>{{msg}}</p>
</div>
</child-component> 子组件
export default{
name:'ChildComponent',
data(){
return{
msg:'张不怂'
}
}
} 最终显示
<div data-v-763db97b="">
<h2 data-v-763db97b="">在父组件中定义子组件的模板</h2>
<p data-v-763db97b="">张不怂</p>
</div>

inline-template使得各个组件的结构混乱,建议不要轻易使用内联模板

全局组件批量自动注册

我们vue组件中引入组件的一般方式是这样的

<template>
<A v-model="searchText" @keydown.enter="search"/>
<B @click="search">
<C name="search"/>
</B>
</template>
<script>
import B from './B'
import C from './C'
import A from './A'
export default {
components: { B, C, A }
}
</script>

有没有办法可以自动全局进行注册呢?答案是肯定的,在你要引入的包含所有组件的文件夹components的同级目录下建register.js,写入下边的代码

const requireComponent = require.context(
'./components', // 其组件目录的相对路径
false, // 是否查询其子目录
/base_[A-Z]\w+\.(vue|js)$/ // 匹配基础组件文件名的正则表达式
) requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName) // 获取组件的 PascalCase 命名
const componentName = upperFirst(
camelCase(
// 剥去文件名开头的 `./` 和结尾的扩展名
fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
)
) // 全局注册组件
Vue.component(
componentName,
componentConfig.default || componentConfig
)
})

然后在你的vue项目的main.js中进行引入,就直接可以使用

import @/register.js;

Vue 的构造器——extend

Vue.extend(options)

用法:使用Vue构造器,创建一个“子类”,参数是一个包含组件选项的对象,其中,data选项中必须是函数

描述:Vue.extend返回的是一个“扩展实例构造器”,也就是预设了部分选项的Vue的实例构造器

自定义一个无参数标签

var foo = Vue.extend({
template: "<p><a :href='url'>{{foo}}</a></p>",
data : function() {
return {
foo : 'vamous',
url : 'https://juejin.im/editor/drafts/5cd2da7a5188253e8c23baf6'
}
}
}); 对应的html
<foo></foo> 此时的页面必然是没有任何效果的,因为扩展实例构造器还需要挂载,如下:
new foo().$mount('#app');

可以利用propsData传递参数

var author = Vue.extend({
template: "<p><a :href='url'>{{bar}} & {{name}}</a></p>",
data : function() {
return {
bar : 'vamous',
url : 'https://juejin.im/editor/drafts/5cd2da7a5188253e8c23baf6'
}
},
props : ['name']
}); new author({propsData: {name : 'foo'}}).$mount('#author');

vue 修饰符sync深入解析

实现子组件与父组件双向绑定的【sync】修饰符:其实sync这个修饰符是vue1.0就有的,它可以实现父子组件的双向绑定,但是Vue2.0被移除了,直到2.3.0版本发布后,又重新开始启用,【.sync】可以很轻松的实现子组件同步修改父组件的值

如果子组件想修改父组件的值,推荐以update:my-prop-name 的模式触发事件取而代之,也就是这样:

父组件
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
---------------------------------------------------------------
子组件
this.$emit("update:title".newTitle)

而上边的 v-on:update:title="doc.title = $event",本质上就可以用sync这个语法糖来表示,.sync后面紧接的就是父组件中需要被改变的值,看下边的例子体会一下

父组件
<template>
<div>
<child-com :value.sync="text" ></child-com>
</div>
</template>
<script>
export default{
data(){
return {
text:"父组件的值",
}
},
}
</script>
==================================================================================
//子组件中修改父组件的值
<template>
<div @click="post"></div>
</template> <script>
export default{
methods:{
post(){
this.$emit('update:value',"子组件的值")
}
}
}
</script>

本篇基本就是这些,这三篇概述了vue的一些知识点,更多的vue实践还需要在工作中自己总结和挖掘,道阻且长,行则将至~

 
 
 
3赞4赞
 
赞赏
 
更多好文
 

vue高级进阶( 三 ) 组件高级用法及最佳实践的更多相关文章

  1. Vue图片验证码-自定义组件高级版

    最近项目中要用到图片验证码,网上一查有很多,基本都是千篇一律的4位纯数字验证码.首先得感谢那位一代目兄台提供的模板,由于不能满足需求,所以对其进行了改造升级. 经改造的图片验证码能满足一下情形使用:① ...

  2. 【Restful】三分钟彻底了解Restful最佳实践

    REST是英文representational state transfer(表象性状态转变)或者表述性状态转移;Rest是web服务的一种架构风格;使用HTTP,URI,XML,JSON,HTML等 ...

  3. 给HTML初学者的三十条最佳实践

    Nettuts +运营最困难的方面是为很多技能水平不同的用户提供服务.如果我们发布太多高级教程,我的新手用户将无法从中受益.相反也是如此.我们尽我们最大的努力,但如果你觉得你被忽略了请联系我们.这个网 ...

  4. vue组件详解(五)——组件高级用法

    一.递归组件 组件在它的模板内可以递归地调用自己, 只要给组件设置name 的选项就可以了. 示例如下: <div id="app19"> <my-compone ...

  5. vue 组件高级用法实例详解

    一.递归组件 组件在它的模板内可以递归地调用自己, 只要给组件设置name 的选项就可以了. 示例如下: <div id="app19"> <my-compone ...

  6. 【Vue】详解组件的基础与高级用法

    Vue.js 最核心的功能就是组件(Component),从组件的构建.注册到组件间通信,Vue 2.x 提供了更多方式,让我们更灵活地使用组件来实现不同需求. 一.构建组件 1.1 组件基础 一个组 ...

  7. Vue.js 源码分析(二十七) 高级应用 异步组件 详解

    当我们的项目足够大,使用的组件就会很多,此时如果一次性加载所有的组件是比较花费时间的.一开始就把所有的组件都加载是没必要的一笔开销,此时可以用异步组件来优化一下. 异步组件简单的说就是只有等到在页面里 ...

  8. Vue.js 源码分析(二十八) 高级应用 transition组件 详解

    transition组件可以给任何元素和组件添加进入/离开过渡,但只能给单个组件实行过渡效果(多个元素可以用transition-group组件,下一节再讲),调用该内置组件时,可以传入如下特性: n ...

  9. vue从入门到进阶:组件Component详解(六)

    一.什么是组件? 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功 ...

  10. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

随机推荐

  1. Corundum:100G NIC学习(二)——仿真

    前情提要:搭建corundum仿真环境(一)https://www.cnblogs.com/shroud404/articles/15364812.html 三.Running test 接上文,梳理 ...

  2. opc ua与opc da区别

    opc ua与opc da区别_OPC,OPCDA,OPCUA傻傻搞不清楚,走过路过不妨看一看 转自:https://blog.csdn.net/weixin_39624774/article/det ...

  3. C++标准库string学习笔记

    string概述 作为c++语言用作字符串处理的标准库,和Python字符串类型有较多相似之处.可以使用'='进行赋值,"=="来比较,"+"进行拼接. 构造函 ...

  4. input输入框限制输入

    <input type="password" value="" id="pwd" class="Rectangle-1188 ...

  5. React父组件如何调用子组件方法,访问子组件State

    /** * * Author: shujun * Date: 2020-10-25 */ import React from 'react'; import {message} from 'antd' ...

  6. EF和dapper

    EF:重量级ORM的代表 优点: 1.不关心sql怎么写, 2.开发速度快,和linq结合,有效提高开发效率 3.code first,代码优先,不用关心数据库结构,代码先行. 4.跨数据库,只需要把 ...

  7. SP2-0750: You may need to set ORACLE_HOME to your Oracle software directory 解决办法

    [oracle@localhost oracle]$ ./sqlplus Error 6 initializing SQL*Plus Message file sp1<lang>.msb ...

  8. 7.Object

    Object类 超类.基类,所以类的直接或间接父类,位于继承树的最顶层 任何类,如没有书写extends显示继承某个类,都默认直接继承Object类,否则为间接继承 Object类中所定义的方法,是所 ...

  9. String、StringBuffer、StringBuilder他们的区别

    String.StringBuffer.StringBuilder他们的区别 String: String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,然后将指针新的对 ...

  10. js把一个数组的数据平均到几个数组里面

    arr 原始数组数据 count  每个数组里面元素个数 function splitIpLit(arr,count) { let i = 0; let newArr = []; while(i &l ...