• Vue2进阶之Vue2高级用法


    mixin

    示例一

    App.vue

    <template>
      <div id="app">
      div>
    template>
    
    <script>
    const mixin2={
      created(){
        console.log("mixin created");
      }
    }
    
    
    export default {
      name: 'App',
      mixins:[mixin2],
      data(){
        return {
          message:"inner Hello world"
        }
      },
      created(){
        console.log("inner created");
      }
    }
    script>
    
    <style>
    style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    main.js

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    const mixin1={
      created:function(){
        console.log("global created");
        console.log("message",this.$data.message);
      }
    }
    
    Vue.mixin(mixin1)
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    请添加图片描述

    示例二

    App.vue

    <template>
      <div id="app">
      div>
    template>
    
    <script>
    const mixin2={
      created(){
        // console.log("mixin created");
      },
      data(){
        return {
          message:"mixin message"
        }
      }
    }
    
    
    export default {
      name: 'App',
      mixins:[mixin2],
      data(){
        return {
          message:"inner message"
        }
      },
      created(){
        // console.log("inner created");
      }
    }
    script>
    
    <style>
    style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    main.js

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    const mixin1={
      created:function(){
        // console.log("global created");
        console.log("message",this.$data.message);
      },
      data(){
        return{
          message:"global message"
        }
      }
    }
    
    Vue.mixin(mixin1)
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    请添加图片描述
    global注入到new Vue实例上,然后在App.vue的实例中执行自己当前的data

    与Vue实例执行顺序有关,先进行当前实例化声明(全局注入),然后再实例化声明的时候注入我们内部的mixin,是外部的的global更高一点

    • 面试题:如果我们不想使用global进行注入的话,我们应该怎么做?(在Vue2中,除了mixin之外的话,如果不希望导致全局影响,还有什么方法避免这种问题?)
      使用插件,插件化可以解决全局注入的问题

    plugin插件

    Vue-router、Vuex等也是插件,通过插件注入进去的
    Vue-router
    Vue-router关于插件的内容
    Vuex

    • 如果要找源码的入口,可以找package.json中对应的入口
      [Vuex的package.json请添加图片描述

    请添加图片描述
    install的方法,将全部内容挂载到Vue的构造函数上,通过use方法挂载到Vue实例上

    插件列表

    Vue2中的VueRouter解析:

    // for Vue2
    // 这两行导入了Vue Router 提供的两个组件
    import View from './components/view'   //导入RouterView  渲染当前路由对应的组件
    import Link from './components/link'  //导入RouterLink   链接组件,导航到不同的路由
      
    export let _Vue  //定义全局变量,存储当前的Vue构造函数
    
    export function install (Vue) {   //Vue插件的入口函数,接受Vue构造函数作为参数
      if (install.installed && _Vue === Vue) return  //检查这个插件是否已经安装,如果安装则返回
      install.installed = true   //没有安装则设置为true
    
      _Vue = Vue  //并且将Vue构造函数保存到_Vue变量中
    
      const isDef = v => v !== undefined   //isDef用于检查变量是否定义
    
      const registerInstance = (vm, callVal) => {  //用于注册路由实例, vm:当前的 Vue 组件实例。callVal:传递给 registerRouteInstance 函数的值
      //函数首先检查 _parentVnode 是否存在,然后检查 _parentVnode.data 和 _parentVnode.data.registerRouteInstance 是否存在。如果所有这些属性都存在,则调用 registerRouteInstance 函数,并将 vm 和 callVal 作为参数传递。
        let i = vm.$options._parentVnode    
    
        if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
          i(vm, callVal)
        }
      }
    
      // 全局注入
      Vue.mixin({
        beforeCreate () {
          if (isDef(this.$options.router)) {  //如果存在,则意味着这个组件或其父组件中定义了路由
            this._routerRoot = this             //当前组件实例设置为路由根实例
            this._router = this.$options.router  //便于后续访问路由实例
            this._router.init(this)   //初始化路由
            // 定义响应式路由对象,为当前组件实例定义响应式_route属性,初始化为当前路由对象,当路由变化时,组件会响应式的更新
            Vue.util.defineReactive(this, '_route', this._router.history.current)
          } else {
            // 如果当前组件没有定义路由,则查找父组件的路由根实例,并且赋值给this._routerRoot
            // 若当前父组件也没有定义路由,则当前组件本身 就是路由根实例
            this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
          }
          registerInstance(this, this)
        },
        destroyed () {
          registerInstance(this)
        }
      })
    
      // Vue原型添加 $router 属性,可以在Vue组件中通过 this.$router访问到路由实例
      Object.defineProperty(Vue.prototype, '$router', {
        get () { return this._routerRoot._router }
      })
    
      // Vue原型添加 $route 属性,可以在Vue组件中通过 this.$route访问到当前路由对象
      Object.defineProperty(Vue.prototype, '$route', {
        get () { return this._routerRoot._route }
      })
    
      // 注册全局组件,将RouterView和RouterLink注册为全局组件,使得在任何Vue组件中使用他们
      Vue.component('RouterView', View)
      Vue.component('RouterLink', Link)
    
      // 定义路由钩子合并策略
      // 获取Vue.js配置中的选项合并策略,并且赋值给strats变量【在 Vue.js 中,组件选项(如 data、methods、computed 等)可能会在父组件和子组件中同时定义,选项合并策略就是用来决定当父组件和子组件的相同选项冲突时如何合并的】
      const strats = Vue.config.optionMergeStrategies
      // 将 strats.created 的合并策略赋值给 beforeRouteEnter、beforeRouteLeave 和 beforeRouteUpdate 这三个路由守卫
      strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
      // beforeRouteEnter、beforeRouteLeave 和 beforeRouteUpdate 并不是 Vue 组件的默认选项,而是 Vue Router 提供的路由守卫
      // 这段代码中,它们被赋予了与 created 生命周期钩子相同的合并策略
      // 这意味着,如果这些路由守卫在父组件和子组件中都被定义,那么它们会按照 created 生命周期钩子的合并策略进行合并
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    Vue3中的VueRouter解析:

    
        // for Vue3
        install(app: App) {
          const router = this
          // 将RouterLink和RouterView注册到Vue应用中,这样就可以在应用的组件中使用他们
          app.component('RouterLink', RouterLink)
          app.component('RouterView', RouterView)
          // 将路由实例设置为Vue应用的全局属性$router,这样就可以在任何组件中通过this.$router访问路由实例了
          app.config.globalProperties.$router = router
          // 定义响应式的$route,用于获取当前的路由对象
          Object.defineProperty(app.config.globalProperties, '$route', {
            enumerable: true,
            get: () => unref(currentRoute),
          })
    
          // 用于浏览器环境下,如果路由未启动,并且当前的路由是初始路由的时候,则启动路由
          if (
            isBrowser &&
            !started &&
            currentRoute.value === START_LOCATION_NORMALIZED
          ) {
            // 启动路由
            started = true
            push(routerHistory.location).catch(err => {
              if (__DEV__) warn('Unexpected error when starting the router:', err)
            })
          }
    
          // 创建响应式路由对象,该对象包含了当前路由的所有属性,并且这些属性都是响应式的
          const reactiveRoute = {} as {
            [k in keyof RouteLocationNormalizedLoaded]: ComputedRef<
              RouteLocationNormalizedLoaded[k]
            >
          }
          for (const key in START_LOCATION_NORMALIZED) {
            // @ts-expect-error: the key matches
            reactiveRoute[key] = computed(() => currentRoute.value[key])
          }
    
          // 提供了路由相关的数据,这样其他组件可以通过inject方法获取这些数据
          app.provide(routerKey, router)
          app.provide(routeLocationKey, reactive(reactiveRoute))
          app.provide(routerViewLocationKey, currentRoute)
    
          // 修改了 Vue 应用的卸载方法,卸载应用之前,执行了一些与路由相关的清理工作
          const unmountApp = app.unmount
          installedApps.add(app)
          app.unmount = function () {
            installedApps.delete(app)
            // the router is not attached to an app anymore
            if (installedApps.size < 1) {
              // invalidate the current navigation
              pendingLocation = START_LOCATION_NORMALIZED
              removeHistoryListener && removeHistoryListener()
              removeHistoryListener = null
              currentRoute.value = START_LOCATION_NORMALIZED
              started = false
              ready = false
            }
            unmountApp()
          }
    
          // 添加开发工具集成 
          // 如果当前是开发环境,或开启了开发工具集成,并且代码运行在浏览器环境下
          if ((__DEV__ || __FEATURE_PROD_DEVTOOLS__) && isBrowser) {
            addDevtools(app, router, matcher)   //则添加与Vue Devtools的集成
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    自定义指令

    全局中定义
    在这里插入图片描述
    局部中定义:
    在这里插入图片描述

    • bind:初始化调用
    • unbind:解绑调用
    • inserted:指定对应的元素->绑定到父节点的时候

    App.vue:

    <template>
      <div>
       
        <div id="hook-arguments-example" v-demo:foo.a.b="message">div>
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          message: 'hello!'
        }
      },
      directives:{
        demo:{
                bind: function (el, binding, vnode) {
                    var s = JSON.stringify
                    el.innerHTML =
                    'name: '       + s(binding.name) + '
    '
    + 'value: ' + s(binding.value) + '
    '
    + 'expression: ' + s(binding.expression) + '
    '
    + 'argument: ' + s(binding.arg) + '
    '
    + 'modifiers: ' + s(binding.modifiers) + '
    '
    + 'vnode keys: ' + Object.keys(vnode).join(', ') console.log("vnode",vnode); } } } }
    script> <style scoped> style>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

    vue-element-admin

    权限验证:v-permission

    插件化的方式注入的
    在这里插入图片描述
    指令实现的功能:
    在这里插入图片描述

    const checkPermission=(el,binding)=>{
        const {value}=binding  
        if(value instanceof Array){
            if(!value.length){
               //没有内容就用父节点删除子节点
                el.parentNode.removeChild(el)
            }
            const roles=store.rule; //当前用户的权限
            //查找是否有权限
            const hasPermission=roles.some(role=>value.includes(role))
            //没有权限就删除
            if(!hasPermission){
                el.parentNode.removeChild(el)
            }
        }else{
            throw new Error("type error")
        }
    }
    
    
    Vue.directives('permission',{
        inserted(el,binding){
            checkPermission(el,binding)
        },
        update(el,binding){
            checkPermission(el,binding)
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    Google搜索东西举例:github awesome vue directive 在源代码中寻找

    slot插槽

    v-slot:基于web components衍生出来的
    就当做占位符来看待
    作用域插槽已经废弃了

    filter过滤器

    <template>
      <div>
        {{ time|timeFormat }}
      div>
    template>
    
    <script>
    import dayjs from 'dayjs'
    export default {
      data() {
        return {
            time:1713401633460
        }
      },
      filters:{
        timeFormat(value,str="YYYY-MM-DD HH:mm:ss"){
            return dayjs(value).format(str)
        }
      }
    }
    script>
    
    <style scoped>
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述
    要求:1.Vue官网自己过一遍

  • 相关阅读:
    手把手带你学SQL—牛客网SQL 别名
    SPARKSQL3.0-Catalog源码剖析
    14:00面试,14:06就出来了,问的问题有点变态。。。
    web前端期末大作业:基于HTML+CSS+JavaScript制作我的音乐网站(带设计报告)
    Verilog实现SPI通信协议驱动设计
    2023年中国液压剪行业供需分析:随着基础设施建设发展,销量同比增长6.7%[图]
    最近收藏的好用免费API集合
    2023.9.21 组会记录
    导出oracle远程数据库到本地
    C语言:多进程的详细介绍
  • 原文地址:https://blog.csdn.net/qq_34306228/article/details/137811081