【笔记】Vue Element+Node.js开发企业通用管理后台系统——Vue进阶(上)


http://www.youbaobao.xyz/admin-docs/guide/base/vue.html


一、$emit 和 $on

实例:$emit 和 $on

$emit 和 $on主要负责事件的定义和消费,实现逻辑的解耦

<html>
  <head>
    <title>$emit 和 $on</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <button @click="boost">触发事件</button>
    </div>
    <script>
      new Vue({
        el: '#root',
        data() {
          return {
            message: 'hello vue'
          }
        },
        created() {
          this.$on('my_events', this.handleEvents)
        },
        methods: {
          handleEvents(e) {
            console.log(this.message, e)
          },
          boost() {
            this.$emit('my_events', 'my params')            
          }
        }
      })
    </script>
  </body>
</html>

1.$on

官方文档:https://cn.vuejs.org/v2/api/#vm-on

通过断点调试分析

  • $on传入两个参数,绑定的事件名称和事件方法。
  • 源码中第一步创建获取vue实例:var vm = this
  • 第二步 判断事件名称是否是数组
    • 是,使用迭代的方式继续调用$on
    • 否,vm._events[event]判空,为空则赋予它一个空数组,然后把需要绑定的事件方法push进去
  • 最后将处理后的vue实例返回

通过第二步可知,可以多个事件绑定一个执行方法,也可以一个事件同时绑定多个执行方法

2.$emit

官方文档:https://cn.vuejs.org/v2/api/#vm-emit

通过断点调试分析

  • $emit传入一个参数,绑定事件方法。
  • 源码中第一步创建获取vue实例:var vm = this
  • 第二步,将事件名称转为小写赋予变量lowerCaseEvent:var lowerCaseEvent = event.toLowerCase()
  • 第三步:做一些检查(略)
  • 第四步:从vm._events[event]中拿出事件方法,判空
  • 第五步:是多个事件方法就转数组
  • 。。。

通过分析可知,$emit中出现error并不会中断执行只是使用try-catch抛出异常

二、directive 用法

官方文档:https://cn.vuejs.org/v2/api/#Vue-directive

实例:directive 用法

<html>
  <head>
    <title>directive 用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <div v-loading="isLoading">{{data}}</div>
      <button @click="update">更新</button>
    </div>
    <script>
      Vue.directive('loading', {
        update(el, binding, vnode) {
          if (binding.value) {
            const div = document.createElement('div')
            div.innerText = '加载中...'
            div.setAttribute('id', 'loading')
            div.style.position = 'absolute'
            div.style.left = 0
            div.style.top = 0
            div.style.width = '100%'
            div.style.height = '100%'
            div.style.display = 'flex'
            div.style.justifyContent = 'center'
            div.style.alignItems = 'center'
            div.style.color = 'white'
            div.style.background = 'rgba(0, 0, 0, .7)'
            document.body.append(div)
          } else {
            document.body.removeChild(document.getElementById('loading'))
          }
        }
      })
      new Vue({
        el: '#root',
        data() {
          return {
            isLoading: false,
            data: ''
          }
        },
        methods: {
          update() {
            this.isLoading = true
            setTimeout(() => {
              this.data = '用户数据'
              this.isLoading = false
            }, 3000)
          }
        }
      })
    </script>
  </body>
</html>
  • update的参数:
    • el:需要进行loading操作的DOM对象
    • binding:更新状态(是否在更新)
    • vnode:转化后的虚拟DOM对象

vue自定义指令VNode详解

VNode虚拟DOM学习

  • 若直接传入function:如下,会直接把指令添加到bind和update生命周期当中
    • Vue.directive(‘loading’, {update(…) {}})
    • Vue.directive(‘loading’, function update(…) {})

需要改造的地方:

else {
    const div = document.getElementById('loading')
    div && document.body.removeChild(div)
}

三、Vue.component 用法

官方文档:https://cn.vuejs.org/v2/api/#Vue-component

实例:Vue.component 用法

<html>
  <head>
    <title>Vue.component 用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <Test :msg="message"></Test>
    </div>
    <script>
      Vue.component('Test', {
        template: '<div>{{msg}}</div>',
        props: {
          msg: {
            type: String,
            default: 'default message'
          }
        }
      })
      new Vue({
        el: '#root',
        data() {
          return {
            message: "Test Component"
          }
        }
      })
    </script>
  </body>
</html>

源码分析

  • 定义组件需要传入组件名称和一个匿名对象
  • vue.js:5216:ASSET_TYPES.forEach(function (type) {
  • type为component
  • vue.js:5216:Vue[type] = function (id,definition) {
  • id为组件名称;definition为传入的匿名对象
  • 使用正则表达式检验名称合法性
  • 接下来判断类型的同时使用isPlainObject函数判断指定参数是否是一个纯粹的对象
    • vue.js:69:function isPlainObject (obj) {return _toString.call(obj) === '[object Object]'}
    • vue.js:59:var _toString = Object.prototype.toString;

为什么用Object.prototype.toString.call(obj)检测对象类型?

  • vue.js:5230:definition = this.options._base.extend(definition);
  • vue.js:5132:Vue.extend = function (extendOptions) {
  • vue.js:5146:var Sub = function VueComponent (options) {this._init(options);};
    • 构造方法进行组件实例化

四、Vue.extend 用法

官方文档:https://cn.vuejs.org/v2/api/#Vue-extend

实例:Vue.extend 用法

<html>
  <head>
    <title>Vue.extend 用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <Test :msg="message"></Test>
    </div>
    <script>
      const component = Vue.extend({
        template: '<div>{{msg}}</div>',
        props: {
          msg: {
            type: String,
            default: 'default message'
          }
        },
        name: 'Test'
      })
      Vue.component('Test')
      new Vue({
        el: '#root',
        data() {
          return {
            message: "Test Extend Component"
          }
        }
      })
    </script>
  </body>
</html>

主要用来生成组件的构造函数VueComponent

  • vue.js:5132:Vue.extend = function (extendOptions) {
  • vue.js:5146:var Sub = function VueComponent (options) {this._init(options);};
    • 构造方法进行组件实例化

其实本实例作用和上一个相同

五、Vue.extend 进阶用法

官方文档:https://cn.vuejs.org/v2/api/#Vue-extend

实例:Vue.extend 进阶用法

<html>
  <head>
    <title>Vue.extend 用法2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      #loading-wrapper {
        position: fixed;
        top: 0;
        left: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,.7);
        color: #fff;
      }
    </style>
  </head>
  <body>
    <div id="root">
      <button @click="showLoading">显示Loading</button>
    </div>
    <script>
      function Loading(msg) {
        const LoadingComponent = Vue.extend({
          template: '<div id="loading-wrapper">{{msg}}</div>',
          props: {
            msg: {
              type: String,
              default: msg
            }
          },
          name: 'LoadingComponent'
        })
        const div = document.createElement('div')
        div.setAttribute('id', 'loading-wrapper')
        document.body.append(div)
        new LoadingComponent().$mount('#loading-wrapper')
        return () => {
          document.body.removeChild(document.getElementById('loading-wrapper'))
        }
      }
      Vue.prototype.$loading = Loading
      new Vue({
        el: '#root',
        methods: {
          showLoading() {
            const hide = this.$loading('正在加载,请稍等...')
            setTimeout(() => {
              hide()
            }, 2000)
          }
        }
      })
    </script>
  </body>
</html>

给vue实例添加自定义api,实现$loading

  • 使用Vue.prototype.$loading = Loading绑定方法
  • 将字符串'正在加载,请稍等...'作为参数msg传入Loading方法中
  • Vue.extend的返回值赋值给变量LoadingComponent
  • const div = document.createElement('div') 创建div
  • div.setAttribute('id', 'loading-wrapper')起名为loading-wrapper
  • document.body.append(div)进行挂载
  • new LoadingComponent().$mount('#loading-wrapper')实例化一个LoadingComponent对象,并挂载到前面创建的div上(直接覆盖,因此id必须相同,否则后面移除的时候找不到)
    在这里插入图片描述
  • const hide = this.$loading('正在加载,请稍等...'),将this.$loading的返回值() => {document.body.removeChild(document.getElementById('loading-wrapper'))赋值给变量hide,并在赋值过程中执行this.$loadingthis.$loading执行过程中return的内容不执行)
  • hide(),延时执行完毕,执行匿名方法() => {document.body.removeChild(document.getElementById('loading-wrapper'))this.$loading执行过程中return的内容),移除挂在的div
  • ``
    在这里插入图片描述

将一个方法赋值给一个变量的过程中,方法会执行一次,变量获取到的是方法的返回值,而方法的返回值是一个匿名方法(箭头函数),因此变量名即这个匿名函数的方法名,所以这个变量可做方法来用

六、Vue.use 用法

官方文档:https://cn.vuejs.org/v2/api/#Vue-use

实例:Vue.use 用法

<html>
  <head>
    <title>Vue.use 用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      #loading-wrapper {
        position: fixed;
        top: 0;
        left: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,.7);
        color: #fff;
      }
    </style>
  </head>
  <body>
    <div id="root">
      <button @click="showLoading">显示Loading</button>
    </div>
    <script>
      const loadingPlugin = {
        install: function(vm) {
          const LoadingComponent = vm.extend({
            template: '<div id="loading-wrapper">{{msg}}</div>',
            props: {
              msg: {
                type: String,
                default: 'loading...'
              }
            }
          }, 'LoadingComponent')
          function Loading(msg) {
            const div = document.createElement('div')
            div.setAttribute('id', 'loading-wrapper')
            document.body.append(div)
            new LoadingComponent({
              props: {
                msg: {
                  type: String,
                  default: msg
                }
              } 
            }).$mount('#loading-wrapper')
            return () => {
              document.body.removeChild(document.getElementById('loading-wrapper'))
            }
          }
          vm.prototype.$loading = Loading
        }
      }
      Vue.use(loadingPlugin)
      new Vue({
        el: '#root',
        methods: {
          showLoading() {
            const hide = this.$loading('正在加载,请稍等...')
            setTimeout(() => {
              hide()
            }, 2000)
          }
        }
      })
    </script>
  </body>
</html>

将上节的功能做成一个插件,通过Vue.use进行加载
在这里插入图片描述
在这里插入图片描述
传送门:Vue.use实现原理Vue.use源码分析


b=null;
var a=(b||(b=[]));
console.log(a);
在这里插入图片描述

发布了28 篇原创文章 · 获赞 53 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_32682301/article/details/105349962