前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >47·灵魂前端工程师养成-Vue终极进阶属性

47·灵魂前端工程师养成-Vue终极进阶属性

作者头像
DriverZeng
发布2022-11-08 17:12:46
3800
发布2022-11-08 17:12:46
举报

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


指令Direvtives


如何自己造一个指令

之前我们学习了很多指令,v-if、v-for、v-on、v-bind...等等都是指令

那么今天,我们就来自己造一个指令出来 目标:造出v-x指令,点击即出现一个x

写法一:全局指令

代码语言:javascript
复制
Vue.directive('x',directiveOptions)
// 你就可以在任意组件中使用v-x了。

写法二:局部指令

代码语言:javascript
复制
new Vue({
    ...,
    directives:{
        "x":directiveOptions
    }
})

// v-x只能在该实例中使用

全局指令

main.js

代码语言:javascript
复制
import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;

Vue.directive('x',{
  inserted:function(el){
    el.addEventListener('click',()=>{console.log('x')})
  }
})

new Vue({
  render: h => h(App)
}).$mount('#app')

App.vue

代码语言:javascript
复制
<template>
  <div id="app">
    <img v-x width="25%" src="./assets/logo.png">
    <HelloWorld msg="Hello Vue in CodeSandbox!" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>


菊部指令

只能在Helloworld组件中使用

HelloWorld.vue

代码语言:javascript
复制
<template>
  <div class="hello">
    <h1 v-x>{{ msg }}</h1>
    <h3>Installed CLI Plugins</h3>
    <ul>
      <li>
        <a
          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
          target="_blank"
          rel="noopener"
        >babel</a>
      </li>
      <li>
        <a
          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
          target="_blank"
          rel="noopener"
        >eslint</a>
      </li>
    </ul>
    <h3>Essential Links</h3>
    <ul>
      <li>
        <a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
      </li>
      <li>
        <a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a>
      </li>
      <li>
        <a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a>
      </li>
      <li>
        <a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a>
      </li>
      <li>
        <a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
      </li>
    </ul>
    <h3>Ecosystem</h3>
    <ul>
      <li>
        <a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a>
      </li>
      <li>
        <a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
      </li>
      <li>
        <a
          href="https://github.com/vuejs/vue-devtools#vue-devtools"
          target="_blank"
          rel="noopener"
        >vue-devtools</a>
      </li>
      <li>
        <a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a>
      </li>
      <li>
        <a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  directives:{
    'x':{
      inserted(el){
        el.addEventListener('click',()=>{console.log('x')})
      },
    },
  },
  props: {
    msg: String
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

directiveOptions的属性


bind

代码语言:javascript
复制
bind(el,info,vnode,oldVnode)

类似于created


inserted

代码语言:javascript
复制
inserted(el,info,vnode,oldVnode)

类似于mounted


update

代码语言:javascript
复制
update(el,info,vnode,oldVnode)

类似于updated


componentUpdated

代码语言:javascript
复制
componentUpdated(el,info,vnode,oldVnode)

用的不多。


unbind

代码语言:javascript
复制
unbind(el,info,vnode,oldVnode)

类似于destroyed。


举例子

自制v-on2指令,模拟v-on

先来个v-on

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";

Vue.config.productionTip = false;

new Vue({
  template: `
    <button v-on:click="hi">点我</button>
  `,
  methods:{
    hi(){
      console.log('hi')
    }
  }
}).$mount("#app");

v-on2

代码语言:javascript
复制
import Vue from "vue/dist/vue.js";

Vue.config.productionTip = false;

new Vue({
  directives:{
    'on2':{
      inserted(el,info){
        el.addEventListener(info.arg,info.value)
      },
      unbind(el,info){
        el.removeEventListener(info.arg,info.value)
      }
    }
  },
  template: `
    <button v-on2:click="hi">点我</button>
  `,
  methods:{
    hi(){
      console.log('hi')
    }
  }
}).$mount("#app");

指令的作用

主要是拥有DOM操作 1.Vue实例/组件用于数据绑定、事件监听、DOM更新 2.Vue指令主要目的就是原生DOM操作

减少重复的DOM操作 1.如果某个DOM操作 你经常使用,那就可以封装成指令 2.如果某个DOM操作比较复杂,也可以封装为指令

混入 mixins


混入就是TMD复制

前端就喜欢把简单概念搞复杂,就是做了一个复制的操作...叫的这么高大上。

如果说directives的作用 是减少DOM操作的重复,那么mixins的作用就是减少data,methods,钩子的重复。


场景描述

假设,我们需要在每个组件上添加name和time,

在created、destroyed时,大厨提示,并报出存活时间

一共有五个组件,请问你怎么做? 一、给每个组件添加data和钩子,共五次 二、或者使用mixins减少重复


代码示例

main.js

代码语言:javascript
复制
import Vue from "vue";
import App from "./App.vue"
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

代码语言:javascript
复制
<template>
  <div id="app">
    <Child1 />
    <button>x</button>
    <Child2 />
    <button>x</button>
    <Child3 />
    <button>x</button>
    <Child4 />
    <button>x</button>
    <Child5 />
    <button>x</button>
  </div>
</template>

<script>
  import Child1 from "./components/Child1.vue"
  import Child2 from "./components/Child2.vue"
  import Child3 from "./components/Child3.vue"
  import Child4 from "./components/Child4.vue"
  import Child5 from "./components/Child5.vue"

  export default {
    name: "App",
    components: {
      Child1,
      Child2,
      Child3,
      Child4,
      Child5,
    }
  };
</script>

<style scoped>
  #app {
    font-family: "Avenir", Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
  }
</style>

Child1.vue

代码语言:javascript
复制
<template>
    <div>
        Child1
    </div>
</template>

Child2.vue

代码语言:javascript
复制
<template>
    <div>
        Child2
    </div>
</template>

Child3.vue

代码语言:javascript
复制
<template>
    <div>
        Child3
    </div>
</template>

Child4.vue

代码语言:javascript
复制
<template>
    <div>
        Child4
    </div>
</template>

Child5.vue

代码语言:javascript
复制
<template>
    <div>
        Child5
    </div>
</template>

需求:当Child1出生的时候,写一个Child1出生,点击×就关闭,并且打出Child1死亡了,以及生存时间

Child1.vue

代码语言:javascript
复制
<template>
    <div>
        Child1
    </div>
</template>

<script>
    export default {
        data() {
            return {
                name: "Child1",
                time: undefined
            }
        },
        created() {
            this.time = new Date()
            console.log(`${this.name}出生了`)
        },
        beforeDestroy() {
            const now = new Date()
            console.log(`${this.name}死亡了,共生存了${now - this.time} ms`)
        }
    }
</script>

App.vue

代码语言:javascript
复制
<template>
    <div id="app">
        <Child1 v-if="Child1Visible"/>
        <button @click="Child1Visible=false">x</button>
        <Child2/>
        <button>x</button>
        <Child3/>
        <button>x</button>
        <Child4/>
        <button>x</button>
        <Child5/>
        <button>x</button>
    </div>
</template>

<script>
    import Child1 from "./components/Child1.vue"
    import Child2 from "./components/Child2.vue"
    import Child3 from "./components/Child3.vue"
    import Child4 from "./components/Child4.vue"
    import Child5 from "./components/Child5.vue"

    export default {
        name: "App",
        data() {
            return {
                Child1Visible: true
            }
        },
        components: {
            Child1,
            Child2,
            Child3,
            Child4,
            Child5,
        }
    };
</script>

<style scoped>
    #app {
        font-family: "Avenir", Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }
</style>

那么,如果...Child1-Child5都需要这个需求,怎么办?重复写5遍?

SB才这么做,就是这么直白~~~

首先,我们在src目录下创建一个mixins目录

然后在mixins目录中创建一个log.js文件,将刚才的内容写入

log.js

代码语言:javascript
复制
const log = {
    data() {
        return {
            name: undefined,
            time: undefined
        }
    },
    created() {
        if (!this.name){
            throw new  Error("need name")
        }
        this.time = new Date()
        console.log(`${this.name}出生了`)
    },
    beforeDestroy() {
        const now = new Date()
        console.log(`${this.name}死亡了,共生存了${now - this.time} ms`)
    }
}

export default log

其他的组件如何使用log?

Child1.vue

代码语言:javascript
复制
<template>
    <div>
        {{name}}
    </div>
</template>

<script>
    import log from '../mixins/log'

    export default {
        data() {
            return {
                name: "Child1"
            }
        },
        mixins: [log]
    }
</script>

Child2.vue

代码语言:javascript
复制
<template>
    <div>
        Child2
    </div>
</template>

<script>
    import log from '../mixins/log'

    export default {
        data() {
            return {
                name: "Child2"
            }
        },
        mixins: [log]
    }
</script>

继承extends


继承

此继承非彼继承,这个继承和mixins有点像,都他妈的是复制,就是写法不太一样,所以我们来是想刚才的那个需求。

需求:当Child1出生的时候,写一个Child1出生,点击×就关闭,并且打出Child1死亡了,以及生存时间,然后我们不想每个组件中,都写一个mixins:[log],那么我们及来使用继承。


代码示例

创建一个MyVue.js文件

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

const MyVue = Vue.extend({
    data() {
        return {
            name: undefined,
            time: undefined
        }
    },
    created() {
        if (!this.name) {
            throw new Error("need name")
        }
        this.time = new Date()
        console.log(`${this.name}出生了`)
    },
    beforeDestroy() {
        const now = new Date()
        console.log(`${this.name}死亡了,共生存了${now - this.time} ms`)
    }
})

export default MyVue

Child1.vue

代码语言:javascript
复制
<template>
    <div>
        {{name}}
    </div>
</template>

<script>
    import MyVue from "../MyVue";

    export default {
        extends: MyVue,
        data() {
            return {
                name: "Child1"
            }
        },
    }
</script>

提供 provide 和 注入 inject


一键换肤

举个例子,我们现在有一个需求,一键换肤的功能,默认是蓝色,可以切换为红色。 文字大小:默认正常,可以改成大或者小

祖先栽树(Provide) 后人乘凉(inject)


代码示例

App.vue

代码语言:javascript
复制
<template>
    <div :class="`app theme-${themeName}`">
        <Child1/>
        <button>x</button>
        <Child2/>
        <button>x</button>
        <Child3/>
        <button>x</button>
        <Child4/>
        <button>x</button>
        <Child5/>
        <button>x</button>
    </div>
</template>

<script>
    import Child1 from "./components/Child1.vue"
    import Child2 from "./components/Child2.vue"
    import Child3 from "./components/Child3.vue"
    import Child4 from "./components/Child4.vue"
    import Child5 from "./components/Child5.vue"

    export default {
        name: "App",
        data() {
            return {
                themeName: "blue", // "red"
                fontSize: "normal" // "big" |"small"
            }
        },
        components: {
            Child1,
            Child2,
            Child3,
            Child4,
            Child5,
        }
    };
</script>

<style scoped>
    .app {
        font-family: "Avenir", Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }

    .app.theme-blue button {
        background: blue;
        color: white;
    }

    .app.theme-blue {
        color: darkblue;
    }

    .app.theme-red button {
        background: red;
        color: white;
    }

    .app.theme-red {
        color: darkred;
    }
</style>

换肤按钮组件

在components中创建一个ChangeThemeButton.vue文件

代码语言:javascript
复制
<template>
    <div>
        <button>一键换肤</button>
    </div>
</template>

引用到Child1中

Child1.vue

代码语言:javascript
复制
<template>
    <div>
        Child1
        <ChangeThemeButton/>
    </div>
</template>

<script>
    import ChangeThemeButton from "./ChangeThemeButton"

    export default {
        components: {
            ChangeThemeButton,
        }
    }
</script>

问题就出来了,就是我特么的,Child1.vue组件里面的按钮,点一下,怎么能把别人都换肤了呢?

这就触及到我的知识盲区了...

看标题... 是用provide和inject


provide提供给别人使用

App.vue

代码语言:javascript
复制
<template>
    <div :class="`app theme-${themeName}`">
        <Child1/>
        <button>x</button>
        <Child2/>
        <button>x</button>
        <Child3/>
        <button>x</button>
        <Child4/>
        <button>x</button>
        <Child5/>
        <button>x</button>
    </div>
</template>

<script>
    import Child1 from "./components/Child1.vue"
    import Child2 from "./components/Child2.vue"
    import Child3 from "./components/Child3.vue"
    import Child4 from "./components/Child4.vue"
    import Child5 from "./components/Child5.vue"

    export default {
        name: "App",
        provide() {
            return {
                themeName: this.themeName,
                changeTheme: this.changeTheme,
            }
        },
        data() {
            return {
                themeName: "blue", // "red"
                fontSize: "normal" // "big" |"small"
            }
        }
        ,
        methods: {
            changeTheme() {
                if (this.themeName === 'blue') {
                    this.themeName = 'red'
                } else {
                    this.themeName = 'blue'
                }
            }
        },
        components: {
            Child1,
            Child2,
            Child3,
            Child4,
            Child5,
        }
    };
</script>

<style scoped>
    .app {
        font-family: "Avenir", Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }

    .app.theme-blue button {
        background: blue;
        color: white;
    }

    .app.theme-blue {
        color: darkblue;
    }

    .app.theme-red button {
        background: red;
        color: white;
    }

    .app.theme-red {
        color: darkred;
    }
</style>

ChangeThemeButton.vue

代码语言:javascript
复制
<template>
    <div>
        <button @click="z">当前主题色:{{themeName}}换肤</button>
    </div>
</template>

<script>
    export default {
        inject: ['themeName','changeTheme'],
        methods:{
            z(){
                this.changeTheme()
            }
        }
    }
</script>


字体变化

App.vue

代码语言:javascript
复制
<template>
    <div :class="`app theme-${themeName}  fontSize-${fontSizeName}`">
        <Child1/>
        <button>x</button>
        <Child2/>
        <button>x</button>
        <Child3/>
        <button>x</button>
        <Child4/>
        <button>x</button>
        <Child5/>
        <button>x</button>
    </div>
</template>

<script>
    import Child1 from "./components/Child1.vue"
    import Child2 from "./components/Child2.vue"
    import Child3 from "./components/Child3.vue"
    import Child4 from "./components/Child4.vue"
    import Child5 from "./components/Child5.vue"

    export default {
        name: "App",
        provide() {
            return {
                themeName: this.themeName,
                changeTheme: this.changeTheme,
                changeFontSize: this.changeFontSize,
            }
        },
        data() {
            return {
                themeName: "blue", // "red"
                fontSizeName: "normal" // "big" |"small"
            }
        }
        ,
        methods: {
            changeTheme() {
                if (this.themeName === 'blue') {
                    this.themeName = 'red'
                } else {
                    this.themeName = 'blue'
                }
            },
            changeFontSize(name) {
                if (['normal', 'big', 'small'].indexOf(name) >= 0) {
                    this.fontSizeName = name
                }
            }
        },
        components: {
            Child1,
            Child2,
            Child3,
            Child4,
            Child5,
        }
    };
</script>

<style>
    .app {
        font-family: "Avenir", Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }

    .app.theme-blue button {
        background: blue;
        color: white;
    }

    .app.theme-blue {
        color: darkblue;
    }

    .app.theme-red button {
        background: red;
        color: white;
    }

    .app.theme-red {
        color: darkred;
    }

    .app.fontSize-normal {
        font-size: 16px;
    }

    .app.fontSize-big {
        font-size: 20px;
    }

    .app.fontSize-small {
        font-size: 12px;
    }

    .app button {
        font-size: inherit;
    }
</style>

ChangeThemeButton.vue

代码语言:javascript
复制
<template>
    <div>
        <button @click="z">换肤</button>
        <button @click="changeFontSize('big')">大字</button>
        <button @click="changeFontSize('small')">小字</button>
        <button @click="changeFontSize('normal')">正常字</button>
    </div>
</template>

<script>
    export default {
        inject: ['themeName', 'changeTheme', 'changeFontSize'],
        methods: {
            z() {
                this.changeTheme()
            },
        }
    }
</script>

Child1.vue

代码语言:javascript
复制
<template>
    <div>
        Child1
        <change-theme-button/>
    </div>
</template>

<script>
    import ChangeThemeButton from "./ChangeThemeButton.vue"

    export default {
        components: {
            ChangeThemeButton,
        }
    }
</script>

provide 和 inject总结

代码语言:javascript
复制
作用:大范围的data和method等共用
注意:不能只传themeName不传changeTheme,因为themeName的值是被复制给provide的

// 传递引用也可以,但是不推荐,因为容易失控
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 指令Direvtives
    • directiveOptions的属性
      • 指令的作用
      • 混入 mixins
      • 继承extends
      • 提供 provide 和 注入 inject
        • provide 和 inject总结
        相关产品与服务
        堡垒机
        腾讯云堡垒机(Bastion Host,BH)可为您的 IT 资产提供代理访问以及智能操作审计服务,为客户构建一套完善的事前预防、事中监控、事后审计安全管理体系,助力企业顺利通过等保测评。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档