Vue进阶用法总结

Vue进阶用法总结

本文目录:

  • 1.$emit$on
  • 2.Vue.directive
  • 3.Vue-extend进阶用法:自定义API
  • 4.Vue.use:挂载插件
  • 5.provide和inject
  • 6.过滤器filter
  • 7.监听器 watch的6种用法
  • 8.class 和 style 绑定的高级用法
  • 9.Vue.observable

1.$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>

输出结果是hello vue my params
原理分析:
通过$on成功将自定义事件myEvent挂载到vue实例上,并且指定了ABC为自定义事件触发的回调函数。
this.$on('自定义事件的名字myEvent',回调函数ABC)
通过$emit触发自定义事件ABC,并且将'my params'作为自定义事件的实参传递出去。
this $emit('自定义事件ABC',传递出去的实参)
好处:
Vue通过上面的操作,将事件定义和事件触发解耦,提升了灵活性。

2.Vue.directive

除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。
有的情况下,仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

<div id="root">
    <div v-loading="isLoading">{{data}}</div>
    <button @click="update">更新</button>
</div>

第一个参数loading和元素中的v-loading中的loading必须是一致的

<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>

当点击按钮的时候,页面呈现以下状态:

image.png


3秒后,loading消失,按钮上方会多出来“用户数据”四个字。
自定义指令中传递的三个参数
el: 指令所绑定的元素,可以用来直接操作DOM。
binding: 一个对象,包含指令的多个属性信息。
vnode: Vue编译生成的虚拟节点。
除了 el 之外,其它参数都应该是只读的,切勿进行修改。
如果需要在钩子之间(自定义指令的生命周期)共享数据,建议通过元素的 dataset 来进行。
自定义指令的生命周期
自定义指令有五个生命周期(也叫钩子函数),分别是 bind, inserted, update, componentUpdated, unbind

  • bind:只调用一次,指令第一次绑定到元素时调用
  • inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document中)
  • update:被绑定于元素所在的模板更新时调用,
  • componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
  • unbind:只调用一次,指令与元素解绑时调用。

3.Vue-extend进阶用法:自定义API

<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>

点击按钮,出现lodaing图,2秒后loading自动消失
关键点
1.自定义一个组件LoadingComponent,并且实现这个租金啊,并将其通过$mount挂载到vue上(loading

自定义指令的方法:通过改变某个状态值来实现元素的变动
自定义api的方法:完全主动触发,并且能够很方便的封装为插件,功能更强大,更为推荐

4.Vue.use:挂载插件

我们将loading封装为一个插件,并通过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(VueRouter)、Vue.use(MintUI)。但是用 axios时,就不需要用 Vue.use(axios),这是因为开发者在封装 axios 时,没有写 install 这一步。
install 是默认的方法。当外界在 use 这个组件的时候,就会调用本身的 install 方法,同时传一个 Vue 这个类的参数。

5.provide和inject

已经有了props和vuex,为什么还需要provide?
props跨组件通信很麻烦,vuex学习成本高

<html>
  <head>
    <title>组件通信 provide 和 inject</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <Test></Test>
    </div>
    <script>
      function registerPlugin() {
        Vue.component('Test', {
          template: '<div>{{message}}<Test2 /></div>',
          provide() {
            return {
              elTest: this
            }
          }, // function 的用途是为了获取运行时环境,否则 this 将指向 window
          data() {
            return {
              message: 'message from Test'
            }
          },
          methods: {
            change(component) {
              this.message = 'message from ' + component
            }
          }
        })
        Vue.component('Test2', {
          template: '<Test3 />'
        })
        Vue.component('Test3', {
          template: '<button @click="changeMessage">change</button>',
          inject: ['elTest'],
          methods: {
            changeMessage() {
              this.elTest.change(this.$options._componentTag)
            }
          }
        })
      }
      Vue.use(registerPlugin)
      new Vue({
        el: '#root'
      })
    </script>
  </body>
</html>

上面的代码Test1通过provide把自身映射为elTest,经过传递,Test3页可以直接通过inject接收到elTest

6.过滤器filter

<html>
  <head>
    <title>过滤器 filter</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="root">
      {{message | lower}}
    </div>
    <script>
      new Vue({
        el: '#root',
        filters: {
          lower(value) {
            return value.toLowerCase()
          }
        },
        data() {
          return {
            message: 'Hello Vue'
          }
        }
      })
    </script>
  </body>
</html>

通过过滤器lower可以很方便的去改变数据。
上面演示的是组件过滤器的用法,另外还可以定义全局过滤器

Vue.filter('globalFilter',function(value){
    return value + '111'
))

7.监听器 watch的6种用法

6种方法的DOM元素都是一样的

<div id="root1">
  <h3>Watch 用法5:绑定多个 handler</h3>
  <input v-model="message">
  <span>{{copyMessage}}</span>
</div>

id值root对应的是root1~root6
root1.监听message属性,当message发生变化的话,触发逻辑代码
root2.message对应的字符串,vue会去methods中寻找对应的方法
root3.deepMessage后面跟的是一个对象,handler对应的是methods中的方法,deep为true代表深度监听
root4:immediate属性代表页面加载完成后就立刻执行一次监听事件
root5:messag后面跟的是一个数组,数组中可以依次绑定多个事件
root6:通过'deepMessage.a.b'来深度监听某个特定属性,而不是全部

    <script>
      new Vue({
        el: '#root',
        watch: {
          message(value) {
            this.copyMessage = value
          }
        },
        data() {
          return {
            message: 'Hello Vue',
            copyMessage: ''
          }
        }
      })
      new Vue({
        el: '#root2',
        watch: {
          message: 'handleMessage'
        },
        data() {
          return {
            message: 'Hello Vue',
            copyMessage: ''
          }
        },
        methods: {
          handleMessage(value) {
            this.copyMessage = value
          }
        }
      })
      new Vue({
        el: '#root3',
        watch: {
          deepMessage: {
            handler: 'handleDeepMessage',
            deep: true
          }
        },
        data() {
          return {
            deepMessage: {
              a: {
                b: 'Deep Message'
              }
            },
            copyMessage: ''
          }
        },
        methods: {
          handleDeepMessage(value) {
            this.copyMessage = value.a.b
          }
        }
      })
      new Vue({
        el: '#root4',
        watch: {
          message: {
            handler: 'handleMessage',
            immediate: true,
          }
        },
        data() {
          return {
            message: 'Hello Vue',
            copyMessage: ''
          }
        },
        methods: {
          handleMessage(value) {
            this.copyMessage = value
          }
        }
      }),
      new Vue({
        el: '#root5',
        watch: {
          message: [{
            handler: 'handleMessage',
          },
          'handleMessage2',
          function(value) {
            this.copyMessage = this.copyMessage + '...'
          }]
        },
        data() {
          return {
            message: 'Hello Vue',
            copyMessage: ''
          }
        },
        methods: {
          handleMessage(value) {
            this.copyMessage = value
          },
          handleMessage2(value) {
            this.copyMessage = this.copyMessage + '*'
          }
        }
      })
      new Vue({
        el: '#root6',
        watch: {
          'deepMessage.a.b': 'handleMessage'
        },
        data() {
          return {
            deepMessage: { a: { b: 'Hello Vue' } },
            copyMessage: ''
          }
        },
        methods: {
          handleMessage(value) {
            this.copyMessage = value
          }
        }
      })
    </script>
  </body>
</html>

8.class 和 style 绑定的高级用法

<html>
  <head>
    <title>class 和 style 绑定的高级用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <div :class="['active', 'normal']">数组绑定多个class</div>
      <div :class="[{active: isActive}, 'normal']">数组包含对象绑定class</div>
      <div :class="[showWarning(), 'normal']">数组包含方法绑定class</div>
      <div :style="[warning, bold]">数组绑定多个style</div>
      <div :style="[warning, mix()]">数组包含方法绑定style</div>
      <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">style多重值</div>
    </div>
    <script>
      new Vue({
        el: '#root',
        data() {
          return {
            isActive: true,
            warning: {
              color: 'orange'
            },
            bold: {
              fontWeight: 'bold'
            }
          }
        },
        methods: {
          showWarning() {
            return 'warning'
          },
          mix() {
            return {
              ...this.bold,
              fontSize: 20
            }
          }
        }
      })
    </script>
  </body>
</html>

9.Vue.observable

随着组件的细化,很多时候都需要处理组件状态共享的情况, Vuex可以轻松解决这类问题,不过就像 Vuex官方文档所说的,如果应用不够大,为避免代码繁琐冗余,最好不要使用它,接下来介绍的是 vue.js 2.6 新增加的 Observable API ,通过使用这个 api 我们可以应对一些简单的跨组件数据状态共享的情况。
observable()方法,用于设置监控属性,这样就可以监控viewModule中的属性值的变化,从而就可以动态的改变某个元素中的值,监控属性则通过返回一个函数给viewModule对象中的属性,从而来监控该属性。返回的对象可以直接用于渲染函数methods和计算属性computed内,并且会在发生改变时触发相应的更新。
创建store.js文件

import Vue from 'vue'
export const state = Vue.observable({
  screenCars: {},
})
export const mutations = {
  updateScreenCars (payload) {
    state.screenCars = Object.assign({}, payload)
  },
}

index.vue组件中触发:

<template>
    <div>
        <el-button @click="toSave">保存</el-button>
    </div>
</template>

<script>
import {state, mutations} from './store.js'
export default {
  name: 'table_form',
  computed: {
    screenCars() {
      return state.screenCars
    },
  },
  methods: {
    setTest: mutations.updateScreenCars ,
    toSave () {
      this.setTest({a:1})
    },
  },
}
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值