前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue组件开发-高级玩法

Vue组件开发-高级玩法

作者头像
娜姐
发布2020-09-22 10:27:11
2.3K0
发布2020-09-22 10:27:11
举报
文章被收录于专栏:娜姐聊前端

在文章《Vue组件开发三板斧:prop、event、slot》中聊了常用的组件开发常用API和一些采坑心得,这里,再说说一些可能不太常用的高级玩法,可参考https://cn.vuejs.org/v2/api/

1. 组件挂载

方式一:components属性

我们常用的创建组件方式就是文件声明,例如,在一个假设的 headTop.js 或 headTop.vue 文件中定义组件。然后通过components 引入组件,将其挂载在DOM节点上。

代码语言:javascript
复制
// layout.vue文件
<template>
  <div class="fillcontain">
    <head-top></head-top>
    <div class="table_container container">
      <div class="container_wrap">
        <slot></slot>
      </div>
    </div>
  </div>
</template>

<script>
import headTop from '@/components/headTop'

export default {
  name: 'layout',
  components: {
    headTop // 引用组件
  }
}
</script>

<style lang="less">
@import '../style/mixin';
.table_container {
  min-height: calc(100% - 100px);
}
</style>

组件headTop是挂载在组件layout中某个DOM节点下。

方式二:$mount

还有两种方式可以创建组件:

  • new Vue()
  • Vue.extend()

new Vue()创建一个 Vue 实例时,都会有一个选项 el,可以用来指定实例的根节点。如果不写 el 选项,那组件就处于未挂载状态。看看最顶层的App.vue是如何挂载到根节点上的:

代码语言:javascript
复制
import App from './App'
......
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})

Vue.extend 是基于 Vue 构造器,创建一个“子类”,它的参数跟 new Vue 的基本一样,但是data写法和组件类似,需要返回一个函数。

代码语言:javascript
复制
import Vue from 'vue';

const AlertComponent = Vue.extend({
  template: '<div>{{ message }}</div>',
  data () {
    return {
      message: 'Hello world!'
    };
  },
});

Vue.extend是无法挂载组件的,此时需要:

  1. 使用$mount 渲染组件或者渲染并挂载组件
  2. 使用JS原生方法,挂载组件
代码语言:javascript
复制
// 方式一:仅仅渲染
const component = new AlertComponent().$mount();
// 通过JS方法组件添加到body节点上
document.body.appendChild(component.$el);

// 方式二:渲染挂载同时做
// 创建并挂载到 #app (会替换 #app)
new AlertComponent().$mount('#app')

应用场景:最常见的应该是自定义全局消息弹窗了。需要将组件挂载在body根节点上,此时,就可以通过$mount指定挂载节点。


同步歪歪一下React......

React 16 的portal也有异曲同工之妙。 portal可以帮助我们在JSX中跟普通组件一样直接使用dialog, 但是又可以让dialog内容层级不在父组件内,而是显示在独立于原来app在外的同层级组件。

HTML:

代码语言:javascript
复制
<div id="app-root"></div>
// 这里为我们定义Dialog想要放入的位置
<div id="modal-root"></div>

JS:

代码语言:javascript
复制
const modalRoot = document.getElementById('modal-root');

// Let's create a Modal component that is an abstraction around the portal API.
class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  }

  componentDidMount() {
    // Append the element into the DOM on mount. We'll render
    // into the modal container element (see the HTML tab).
    modalRoot.appendChild(this.el);
  }

  componentWillUnmount() {
    // Remove the element from the DOM when we unmount
    modalRoot.removeChild(this.el);
  }
  
  render() {
    // Use a portal to render the children into the element
    return ReactDOM.createPortal(
      this.props.children,
      this.el,
    );
  }
}

2. 渲染函数 render

Vue.js 2.0使用了 Virtual DOM(虚拟 DOM)来更新 DOM 节点,提升渲染性能。

一般我们写 Vue.js 组件,模板都是写在 <template> 内的,但它并不是最终呈现的内容,在 Vue.js 编译阶段,会解析为 Virtual DOM。与 DOM 操作相比,Virtual DOM 是基于 JavaScript 计算的,所以开销会小很多。下图演示了 Virtual DOM 运行的过程(来自网络):

vue.png

Vue.js 的 Render 函数就是将template 的内容改写成一个 JavaScript 对象。官网文档上有个极好的例子:https://cn.vuejs.org/v2/guide/render-function.html

代码语言:javascript
复制
Vue.component('my-component', {
  render: (h)=> {
    return h('div', {
            style: {
              color: 'red'
            }
          }, '自定义内容');
  }
})

应用场景:如果模板条件太多,用JS处理比HTML处理更加便利时,推荐使用render函数。

3. 递归组件

递归组件就是指组件在模板中调用自己,其核心是:在组件中设置一个 name 选项。如下:

代码语言:javascript
复制
<template>
  <div>
   这是一个组件,递归调用自己
   <my-component></my-component> 
  </div>
</template>
<script>
  export default {
    name: 'my-component'
  }
</script>

当然,上面的代码是有问题的。如果直接运行,会抛出 max stack size exceeded 的错误,因为没有终止条件,所以组件会无限的递归下去,循环至死。

所以,递归组件的第二个核心:设置终止条件。 改造一下上面的代码:

代码语言:javascript
复制
<template>
  <div>
   这是一个组件,递归调用3次
   <my-component :count="count + 1" v-if="count <= 3"></my-component>
  </div>
</template>
<script>
  export default {
    name: 'my-component',
    props: {
      count: {
        type: Number,
        default: 1
      }
    }
  }
</script>

应用场景:树形组件

4. 组件通信:provide / inject

这对选项需要一起使用!( Vue.js 2.2.0 版本后新增的 API) 允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

是不是和React context很相似!!

代码语言:javascript
复制
// 父级组件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}

// 子组件注入 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}

应用场景:某种意义上可以代替Vuex。如果你的项目只是需要全局共享一些公共状态信息,比如用户名,那么,用provide / inject足够了。

比如,在app.vue中注入根组件。

代码语言:javascript
复制
<script>
  export default {
    provide () {
      return {
        app: this
      }
    },
    data () {
      return {
        userInfo: null
      }
    },
    methods: {
      getUserInfo () {
        // 通过 ajax 获取用户信息后,赋值给 this.userInfo
        $.ajax('/user/info', (data) => {
          this.userInfo = data;
        });
      }
    },
    mounted () {
      this.getUserInfo();
    }
  }
</script>

然后,任何组件都可以使用到userInfo数据:

代码语言:javascript
复制
<template>
  <div>
    {{ app.userInfo }}
  </div>
</template>
<script>
  export default {
    inject: ['app']
  }
</script>

是不是比用Vuex简洁多了!

5. 数据更新:$set

之前提过,向响应式对象中添加一个属性,该新属性是非响应式的,视图也无法更新。所以为了保证新属性的响应性,可以用此API。

代码语言:javascript
复制
this.$set(data, 'checked', true);

小结

https://cn.vuejs.org/v2/api/是个好东西,多翻翻里面的api,可以发现很多有趣的功能。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 组件挂载
    • 方式一:components属性
      • 方式二:$mount
      • 2. 渲染函数 render
      • 3. 递归组件
      • 4. 组件通信:provide / inject
        • 5. 数据更新:$set
        • 小结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档