专业的编程技术博客社区

网站首页 > 博客文章 正文

一用惊人的Vue实践技巧「值得推荐」

baijin 2024-10-27 08:08:47 博客文章 13 ℃ 0 评论

作者: 子君

转发链接:https://mp.weixin.qq.com/s/p4J9vqDD7-7FFK5tq_CZMA

前言

?

葡萄美酒夜光杯,欲饮琵琶产品催。客户现场君莫笑,古来埋坑几人回?

?

最近一直在开发后台管理系统,日复一日的重复着表单表格表格表单,标准的CV仔,感觉好无聊,如何能在这种无聊的开发过程中去提升自己,小编今天又整理了一波新的Vue实战技巧,这些技巧,不用则已,一用惊人。

Vue实践技巧

10个Vue开发技巧「实践」

Vue原来可以这样写开发效率杠杠的

「干货」学会这些Vue小技巧,可以早点下班和女神约会

Vue真是太好了 壹万多字的Vue知识点 超详细!

更多的Vue 实践项目技巧请见本篇文章最下方,有惊喜等着你!

了解选项合并策略,自定义生命周期钩子函数

当你使用Vue的mixins的时候,是否有发现,如果混入的methods里面的方法与组件的方法同名,则会被组件方法覆盖,但是生命周期函数如果重名,混入的与组件自身的都会被执行,且执行顺序是先混入和自身,这是怎么做到的呢?

1. 了解Vue合并策略

在Vue中,不同的选项有不同的合并策略,比如 data,props,methods是同名属性覆盖合并,其他直接合并,而生命周期钩子函数则是将同名的函数放到一个数组中,在调用的时候依次调用,具体可参考小编前面的一篇文章绝对干货~!学会这些Vue小技巧,可以早点下班和女神约会了

在Vue中,提供了一个api, Vue.config.optionMergeStrategies,可以通过这个api去自定义选项的合并策略。

在代码中打印

console.log(Vue.config.optionMergeStrategies)

控制台打印内容

通过上图可以看到Vue所有选项的合并策略函数,我们可以通过覆盖上面的方法,来自定义合并策略函数,不过一般用不到。

2. 通过合并策略自定义生命周期函数

背景

最近客户给领导反馈,我们的系统用一段时间,浏览器就变得有点卡,不知道为什么。问题出来了,本来想甩锅到后端,但是浏览器问题,没法甩锅啊,那就排查吧。

后来发现页面有许多定时器,ajax轮询还有动画,打开一个浏览器页签没法问题,打开多了,浏览器就变得卡了,这时候我就想如果能在用户切换页签时候将这些都停掉,不久解决了。百度里面上下检索,找到了一个事件visibilitychange,可以用来判断浏览器页签是否显示。

有方法了,就写呗

export default {
  created() {
    window.addEventListener('visibilitychange', this.$_hanldeVisiblityChange)
    // 此处用了hookEvent,可以参考小编前一篇文章
    this.$on('hook:beforeDestroy', () => {
      window.removeEventListener(
        'visibilitychange',
        this.$_hanldeVisiblityChange
      )
    })
  },
  methods: {
    $_hanldeVisiblityChange() {
      if (document.visibilityState === 'hidden') {
        // 停掉那一堆东西
      }
      if (document.visibilityState === 'visible') {
        // 开启那一堆东西
      }
    }
  }
}

通过上面的代码,可以看到在每一个需要监听处理的文件都要写一堆事件监听,判断页面是否显示的代码,一处两处还可以,文件多了就头疼了,这时候小编突发奇想,定义一个页面显示隐藏的生命周期钩子,把这些判断都封装起来,哪里需要点哪里,so easy(点读机记得广告费)。

自定义生命周期钩子函数

定义生命周期函数 pageHidden 与 pageVisible

import Vue from 'vue'

// 通知所有组件页面状态发生了变化
const notifyVisibilityChange = (lifeCycleName, vm) => {
  // 生命周期函数会存在$options中,通过$options[lifeCycleName]获取生命周期
  const lifeCycles = vm.$options[lifeCycleName]
  // 因为使用了created的合并策略,所以是一个数组
  if (lifeCycles && lifeCycles.length) {
    // 遍历 lifeCycleName对应的生命周期函数列表,依次执行
    lifeCycles.forEach(lifecycle => {
      lifecycle.call(vm)
    })
  }
  // 遍历所有的子组件,然后依次递归执行
  if (vm.$children && vm.$children.length) {
    vm.$children.forEach(child => {
      notifyVisibilityChange(lifeCycleName, child)
    })
  }
}

// 添加生命周期函数
export function init() {
  const optionMergeStrategies = Vue.config.optionMergeStrategies
  // 定义了两个生命周期函数 pageVisible, pageHidden
  // 为什么要赋值为 optionMergeStrategies.created呢
  // 这个相当于指定 pageVisible, pageHidden 的合并策略与 created的相同(其他生命周期函数都一样)
  optionMergeStrategies.pageVisible = optionMergeStrategies.beforeCreate
  optionMergeStrategies.pageHidden = optionMergeStrategies.created
}


// 将事件变化绑定到根节点上面
// rootVm vue根节点实例
export function bind(rootVm) {
  window.addEventListener('visibilitychange', () => {
    // 判断调用哪个生命周期函数
    let lifeCycleName = undefined
    if (document.visibilityState === 'hidden') {
      lifeCycleName = 'pageHidden'
    } else if (document.visibilityState === 'visible') {
      lifeCycleName = 'pageVisible'
    }
    if (lifeCycleName) {
      // 通过所有组件生命周期发生变化了
      notifyVisibilityChange(lifeCycleName, rootVm)
    }
  })
}

应用

  1. 在main.js主入口文件引入
import { init, bind } from './utils/custom-life-cycle'

// 初始化生命周期函数, 必须在Vue实例化之前确定合并策略
init()

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

// 将rootVm 绑定到生命周期函数监听里面
bind(vm)
  1. 在需要的地方监听生命周期函数
export default {
  pageVisible() {
    console.log('页面显示出来了')
  },
  pageHidden() {
    console.log('页面隐藏了')
  }
}

provide与inject,不止父子传值,祖宗传值也可以

Vue相关的面试经常会被面试官问道,Vue父子之间传值的方式有哪些,通常我们会回答,props传值,$emit事件传值,vuex传值,还有eventbus传值等等,今天再加一种provide与inject传值,离offer又近了一步。(对了,下一节还有一种)

使用过React的同学都知道,在React中有一个上下文Context,组件可以通过Context向任意后代传值,而Vue的provide与inject的作用于Context的作用基本一样

先举一个例子

使用过elemment-ui的同学一定对下面的代码感到熟悉

<template>
  <el-form :model="formData" size="small">
    <el-form-item label="姓名" prop="name">
      <el-input v-model="formData.name" />
    </el-form-item>
    <el-form-item label="年龄" prop="age">
      <el-input-number v-model="formData.age" />
    </el-form-item>
    <el-button>提交</el-button>
  </el-form>
</template>
<script>export default {
  data() {
    return {
      formData: {
        name: '',
        age: 0
      }
    }
  }
}</script>

看了上面的代码,貌似没啥特殊的,天天写啊。在el-form上面我们指定了一个属性size="small",然后有没有发现表单里面的所有表单元素以及按钮的 size都变成了small,这个是怎么做到的?接下来我们自己手写一个表单模拟一下

自己手写一个表单

我们现在模仿element-ui的表单,自己自定义一个,文件目录如下

自定义表单custom-form.vue

<template>
  <form class="custom-form">
    <slot></slot>
  </form>
</template>
<script>export default {
  props: {
    // 控制表单元素的大小
    size: {
      type: String,
      default: 'default',
      // size 只能是下面的四个值
      validator(value) {
        return ['default', 'large', 'small', 'mini'].includes(value)
      }
    },
    // 控制表单元素的禁用状态
    disabled: {
      type: Boolean,
      default: false
    }
  },
  // 通过provide将当前表单实例传递到所有后代组件中
  provide() {
    return {
      customForm: this
    }
  }
}</script>

在上面代码中,我们通过provide将当前组件的实例传递到后代组件中,provide是一个函数,函数返回的是一个对象

自定义表单项custom-form-item.vue

没有什么特殊的,只是加了一个label,element-ui更复杂一些

<template>
  <div class="custom-form-item">
    <label class="custom-form-item__label">{{ label }}</label>
    <div class="custom-form-item__content">
      <slot></slot>
    </div>
  </div>
</template>
<script>export default {
  props: {
    label: {
      type: String,
      default: ''
    }
  }
}</script>

自定义输入框 custom-input.vue

<template>
  <div
    class="custom-input"
    :class="[
      `custom-input--${getSize}`,
      getDisabled && `custom-input--disabled`
    ]"
  >
    <input class="custom-input__input" :value="value" @input="$_handleChange" />
  </div>
</template>
<script>/* eslint-disable vue/require-default-prop */
export default {
  props: {
    // 这里用了自定义v-model
    value: {
      type: String,
      default: ''
    },
    size: {
      type: String
    },
    disabled: {
      type: Boolean
    }
  },
  // 通过inject 将form组件注入的实例添加进来
  inject: ['customForm'],
  computed: {
    // 通过计算组件获取组件的size, 如果当前组件传入,则使用当前组件的,否则是否form组件的
    getSize() {
      return this.size || this.customForm.size
    },
    // 组件是否禁用
    getDisabled() {
      const { disabled } = this
      if (disabled !== undefined) {
        return disabled
      }
      return this.customForm.disabled
    }
  },
  methods: {
    // 自定义v-model
    $_handleChange(e) {
      this.$emit('input', e.target.value)
    }
  }
}</script>

在form中,我们通过provide返回了一个对象,在input中,我们可以通过inject获取form中返回对象中的项,如上代码inject:['customForm']所示,然后就可以在组件内通过this.customForm调用form实例上面的属性与方法了

**在上面代码中我们使用了自定义v-model,关于自定义v-model可以阅读小编前面的文章绝对干货~!学会这些Vue小技巧,可以早点下班和女神约会了 **

在项目中使用

<template>
  <custom-form size="small">
    <custom-form-item label="姓名">
      <custom-input v-model="formData.name" />
    </custom-form-item>
  </custom-form>
</template>
<script>import CustomForm from '../components/custom-form'
import CustomFormItem from '../components/custom-form-item'
import CustomInput from '../components/custom-input'
export default {
  components: {
    CustomForm,
    CustomFormItem,
    CustomInput
  },
  data() {
    return {
      formData: {
        name: '',
        age: 0
      }
    }
  }
}</script>

执行上面代码,运行结果为:

<form class="custom-form">
  <div class="custom-form-item">
    <label class="custom-form-item__label">姓名</label>
    <div class="custom-form-item__content">
      <!--size=small已经添加到指定的位置了-->
      <div class="custom-input custom-input--small">
        <input class="custom-input__input">
      </div>
    </div>
  </div>
</form>

通过上面的代码可以看到,input组件已经设置组件样式为custom-input--small了

inject格式说明

除了上面代码中所使用的inject:['customForm']写法之外,inject还可以是一个对象。且可以指定默认值

修改上例,如果custom-input外部没有custom-form,则不会注入customForm,此时为customForm指定默认值

{
  inject: {
    customForm: {
      // 对于非原始值,和props一样,需要提供一个工厂方法
      default: () => ({
        size: 'default'
      })
    }
  }
}

如果我们希望inject进来的属性的名字不叫customForm,而是叫parentForm,如下代码

inject: {
    // 注入的属性名称
    parentForm: {
      // 通过 from 指定从哪个属性注入
      from: 'customForm',
      default: () => ({
        size: 'default'
      })
    }
  },
  computed: {
    // 通过计算组件获取组件的size, 如果当前组件传入,则使用当前组件的,否则是否form组件的
    getSize() {
      return this.size || this.parentForm.size
    }
  }

使用限制

  1. provide和inject的绑定不是可响应式的。但是,如果你传入的是一个可监听的对象,如上面的customForm: this,那么其对象的属性还是可响应的。
  2. Vue官网建议provide 和 inject 主要在开发高阶插件/组件库时使用。不推荐用于普通应用程序代码中。因为provide和inject在代码中是不可追溯的(ctrl + f可以搜),建议可以使用Vuex代替。但是,也不是说不能用,在局部功能有时候用了作用还是比较大的。

dispatch和broadcast,这是一种有历史的组件通信方式

dispatch与broadcast是一种有历史的组件通信方式,为什么是有历史的,因为他们是Vue1.0提供的一种方式,在Vue2.0中废弃了。但是废弃了不代表我们不能自己手动实现,像许多UI库内部都有实现。本文以element-ui实现为基础进行介绍。同时看完本节,你会对组件的$parent,$children,$options有所了解。

方法介绍

?

$dispatch: $dispatch会向上触发一个事件,同时传递要触发的祖先组件的名称与参数,当事件向上传递到对应的组件上时会触发组件上的事件侦听器,同时传播会停止。

?

?

$broadcast: $broadcast会向所有的后代组件传播一个事件,同时传递要触发的后代组件的名称与参数,当事件传递到对应的后代组件时,会触发组件上的事件侦听器,同时传播会停止(因为向下传递是树形的,所以只会停止其中一个叶子分支的传递)。

?

$dispatch实现与应用

1. 代码实现

 // 向上传播事件
 // @param {*} eventName 事件名称
 // @param {*} componentName 接收事件的组件名称
 // @param {...any} params 传递的参数,可以有多个
 
function dispatch(eventName, componentName, ...params) {
  // 如果没有$parent, 则取$root
  let parent = this.$parent || this.$root
  while (parent) {
    // 组件的name存储在组件的$options.componentName 上面
    const name = parent.$options.name
    // 如果接收事件的组件是当前组件
    if (name === componentName) {
      // 通过当前组件上面的$emit触发事件,同事传递事件名称与参数
      parent.$emit.apply(parent, [eventName, ...params])
      break
    } else {
      // 否则继续向上判断
      parent = parent.$parent
    }
  }
}

// 导出一个对象,然后在需要用到的地方通过混入添加
export default {
  methods: {
    $dispatch: dispatch
  }
}

2. 代码应用

  • 在子组件中通过$dispatch向上触发事件import emitter from '../mixins/emitter'
    export default {
    name: 'Chart',
    // 通过混入将$dispatch加入进来
    mixins: [emitter],
    mounted() {
    // 在组件渲染完之后,将组件通过$dispatch将自己注册到Board组件上
    this.$dispatch('register', 'Board', this)
    }
    }
  • 在Board组件上通过$on监听要注册的事件export default {
    name: 'Board',
    created() {
    this.$on('register',(component) => {
    // 处理注册逻辑
    })
    }
    }

$broadcast实现与应用

1. 代码实现

  //向下传播事件
  // @param {*} eventName 事件名称
  // @param {*} componentName 要触发组件的名称
  // @param  {...any} params 传递的参数
 
function broadcast(eventName, componentName, ...params) {
  this.$children.forEach(child => {
    const name = child.$options.name
    if (name === componentName) {
      child.$emit.apply(child, [eventName, ...params])
    } else {
      broadcast.apply(child, [eventName, componentName, ...params])
    }
  })
}

// 导出一个对象,然后在需要用到的地方通过混入添加
export default {
  methods: {
    $broadcast: broadcast
  }
}

2. 代码应用

在父组件中通过$broadcast向下触发事件

import emitter from '../mixins/emitter'
export default {
  name: 'Board',
  // 通过混入将$dispatch加入进来
  mixins: [emitter],
  methods:{
  	//在需要的时候,刷新组件
  	$_refreshChildren(params) {
  		this.$broadcast('refresh', 'Chart', params)
  	}
  }
}

在后代组件中通过$on监听刷新事件

export default {
  name: 'Chart',
  created() {
    this.$on('refresh',(params) => {
      // 刷新事件
    })
  }
}

总结

通过上面的例子,同学们应该都能对$dispatch和$broadcast有所了解,但是为什么Vue2.0要放弃这两个方法呢?官方给出的解释是:”因为基于组件树结构的事件流方式实在是让人难以理解,并且在组件结构扩展的过程中会变得越来越脆弱。这种事件方式确实不太好,我们也不希望在以后让开发者们太痛苦。并且 $dispatch 和 $broadcast 也没有解决兄弟组件间的通信问题。“

确实如官网所说,这种事件流的方式确实不容易让人理解,而且后期维护成本比较高。但是在小编看来,不管黑猫白猫,能抓老鼠的都是好猫,在许多特定的业务场景中,因为业务的复杂性,很有可能使用到这样的通信方式。但是使用归使用,但是不能滥用,小编一直就在项目中有使用。

插槽,我要钻到你的怀里

插槽,相信每一位Vue都有使用过,但是如何更好的去理解插槽,如何去自定义插槽,今天小编为你带来更形象的说明。

默认插槽

大学毕业刚上班,穷鬼一个,想着每个月租房还要掏房租,所以小编决定买一个一居室,东拼西凑借了一堆债,终于凑够了首付,买了一个小小的毛坯房。我们可以把这个一居室的毛坯房想象成一个组件,这个房子的户型,面积,楼层都是固定的,但是室内如何装修,摆什么家具,这个却是由你来决定的,房间内部就可以理解为插槽,允许用户去自定义内容。

1. 开发商终于将一居室开发完交房了

<template>
  <!--这是一个一居室-->
  <div class="one-bedroom">
    <!--添加一个默认插槽,用户可以在外部随意定义这个一居室的内容-->
    <slot></slot>
  </div>
</template>

2. 小编要开始装修了

<template>
  <!--这里一居室-->
  <one-bedroom>
    <!--将家具放到房间里面,组件内部就是上面提供的默认插槽的空间-->
    <span>先放一个小床,反正没有女朋友</span>
    <span>再放一个电脑桌,在家还要加班写bug</span>
  </one-bedroom>
</template>
<script>import OneBedroom from '../components/one-bedroom'
export default {
  components: {
    OneBedroom
  }
}</script>

具名插槽

过了几年,小编有了女朋友,准备结婚了,一居室房间肯定不行啊,丈母娘嫌小不同意,没办法,只能又凑钱买大房子,买了一个两居室,因为是两居室,所以有了主卧和次卧之分,装修是否也不能把主卧和次卧装修的一模一样,所以就需要进行区分。将房子想象成组件,那么组件就有两个插槽,并且需要起名字进行区分。

1. 开发商终于开发完交房了

<template>
  <div class="two-bedroom">
    <!--这是主卧-->
    <div class="master-bedroom">
      <!---主卧使用默认插槽-->
      <slot></slot>
    </div>
    <!--这是次卧-->
    <div class="secondary-bedroom">
      <!--次卧使用具名插槽-->
      <slot name="secondard"></slot>
    </div>
  </div>
</template>

2. 小编要卖血攒钱装修了

<template>
  <two-bedroom>
    <!--主卧使用默认插槽-->
    <div>
      <span>放一个大床,要结婚了,嘿嘿嘿</span>
      <span>放一个衣柜,老婆的衣服太多了</span>
      <span>算了,还是放一个电脑桌吧,还要写bug</span>
    </div>
    <!--次卧,通过v-slot:secondard 可以指定使用哪一个具名插槽, v-slot:secondard 也可以简写为 #secondard-->
    <template v-slot:secondard>
      <div>
        <span>父母要住,放一个硬一点的床,软床对腰不好</span>
        <span>放一个衣柜</span>
      </div>
    </template>
  </two-bedroom>
</template>
<script>import TwoBedroom from '../components/slot/two-bedroom'
export default {
  components: {
    TwoBedroom
  }
}</script>

作用于插槽

装修的时候,装修师傅问我洗衣机是要放到卫生间还是阳台,一般情况下开发商会预留放洗衣机的位置。而这个位置可以理解为插槽传的参数,这个就是作用域插槽。

1. 看一下卫生间插槽装了什么参数

<template>
  <div class="two-bedroom">
    <!--其他内容省略-->
    <div class="toilet">
      <!--通过v-bind 可以向外传递参数, 告诉外面卫生间可以放洗衣机-->
      <slot name="toilet" v-bind="{ washer: true }"></slot>
    </div>
  </div>
</template>

2. 把洗衣机放到卫生间

<template>
  <two-bedroom>
    <!--其他省略-->
    <!--卫生间插槽,通过v-slot="scope"可以获取组件内部通过v-bind传的值-->
    <template v-slot:toilet="scope">
      <!--判断是否可以放洗衣机-->
      <span v-if="scope.washer">这里放洗衣机</span>
    </template>
  </two-bedroom>
</template>

插槽默认值

小编的同事不想等期房,所以就买了二手房,二手房前业主都装修好了,可以直接入住。当然也可以重新装修,下面是同事买的二手房。

1. 这是装修好的二手房

<template>
  <div class="second-hand-house">
    <div class="master-bedroom">
      <!--插槽可以指定默认值,如果外部调用组件时没有修改插槽内容,则使用默认插槽-->
      <slot>
        <span>这里有一张水床,玩的够嗨</span>
        <span>还有一个衣柜,有点旧了</span>
      </slot>
    </div>
    <!--这是次卧-->
    <div class="secondary-bedroom">
      <!--次卧使用具名插槽-->
      <slot name="secondard">
        <span>这里有一张婴儿床</span>
      </slot>
    </div>
  </div>
</template>

2. 同事决定先把主卧装修了,以后结婚用

<second-hand-house>
    <!--主卧使用默认插槽,只装修主卧-->
    <div>
      <span>放一个大床,要结婚了,嘿嘿嘿</span>
      <span>放一个衣柜,老婆的衣服太多了</span>
      <span>算了,还是放一个电脑桌吧,还要写bug</span>
    </div>
  </second-hand-house>

结语

?

不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。——文森特?梵高

?

如果喜欢小编,可以加个关注,了解更多干货。同时,小手一挥,艳遇不断。

推荐Vue学习资料文章:

Vue常见的面试知识点汇总(上)「附答案」

Vue常见的面试知识点汇总(下)「附答案」

Kbone原理详解与小程序技术选型

为什么我不再用Vue,改用React?

让Jenkins自动部署你的Vue项目「实践」

20个免费的设计资源 UI套件背景图标CSS框架

Deno将停止使用TypeScript,并公布五项具体理由

前端骨架屏都是如何生成的

Vue原来可以这样写开发效率杠杠的

用vue简单写一个音乐播放组件「附源码」

为什么Vue3.0不再使用defineProperty实现数据监听?

「干货」学会这些Vue小技巧,可以早点下班和女神约会

探索 Vue-Multiselect

细品30张脑图带你从零开始学Vue

Vue后台项目中遇到的技术难点以及解决方案

手把手教你Electron + Vue实战教程(五)

手把手教你Electron + Vue实战教程(四)

手把手教你Electron + Vue实战教程(三)

手把手教你Electron + Vue实战教程(二)

手把手教你Electron + Vue实战教程(一)

收集22种开源Vue模板和主题框架「干货」

如何写出优秀后台管理系统?11个经典模版拿去不谢「干货」

手把手教你实现一个Vue自定义指令懒加载

基于 Vue 和高德地图实现地图组件「实践」

一个由 Vue 作者尤雨溪开发的 web 开发工具—vite

是什么让我爱上了Vue.js

1.1万字深入细品Vue3.0源码响应式系统笔记「上」

1.1万字深入细品Vue3.0源码响应式系统笔记「下」

「实践」Vue 数据更新7 种情况汇总及延伸解决总结

尤大大细说Vue3 的诞生之路「译」

提高10倍打包速度工具Snowpack 2.0正式发布,再也不需要打包器

大厂Code Review总结Vue开发规范经验「值得学习」

Vue3 插件开发详解尝鲜版「值得收藏」

带你五步学会Vue SSR

记一次Vue3.0技术干货分享会

Vue 3.x 如何有惊无险地快速入门「进阶篇」

「干货」微信支付前后端流程整理(Vue+Node)

带你了解 vue-next(Vue 3.0)之 炉火纯青「实践」

「干货」Vue+高德地图实现页面点击绘制多边形及多边形切割拆分

「干货」Vue+Element前端导入导出Excel

「实践」Deno bytes 模块全解析

细品pdf.js实践解决含水印、电子签章问题「Vue篇」

基于vue + element的后台管理系统解决方案

Vue仿蘑菇街商城项目(vue+koa+mongodb)

基于 electron-vue 开发的音乐播放器「实践」

「实践」Vue项目中标配编辑器插件Vue-Quill-Editor

基于 Vue 技术栈的微前端方案实践

消息队列助你成为高薪 Node.js 工程师

Node.js 中的 stream 模块详解

「干货」Deno TCP Echo Server 是怎么运行的?

「干货」了不起的 Deno 实战教程

「干货」通俗易懂的Deno 入门教程

Deno 正式发布,彻底弄明白和 node 的区别

「实践」基于Apify+node+react/vue搭建一个有点意思的爬虫平台

「实践」深入对比 Vue 3.0 Composition API 和 React Hooks

前端网红框架的插件机制全梳理(axios、koa、redux、vuex)

深入Vue 必学高阶组件 HOC「进阶篇」

深入学习Vue的data、computed、watch来实现最精简响应式系统

10个实例小练习,快速入门熟练 Vue3 核心新特性(一)

10个实例小练习,快速入门熟练 Vue3 核心新特性(二)

教你部署搭建一个Vue-cli4+Webpack移动端框架「实践」

2020前端就业Vue框架篇「实践」

详解Vue3中 router 带来了哪些变化?

Vue项目部署及性能优化指导篇「实践」

Vue高性能渲染大数据Tree组件「实践」

尤大大细品VuePress搭建技术网站与个人博客「实践」

10个Vue开发技巧「实践」

是什么导致尤大大选择放弃Webpack?【vite 原理解析】

带你了解 vue-next(Vue 3.0)之 小试牛刀【实践】

带你了解 vue-next(Vue 3.0)之 初入茅庐【实践】

实践Vue 3.0做JSX(TSX)风格的组件开发

一篇文章教你并列比较React.js和Vue.js的语法【实践】

手拉手带你开启Vue3世界的鬼斧神工【实践】

深入浅出通过vue-cli3构建一个SSR应用程序【实践】

怎样为你的 Vue.js 单页应用提速

聊聊昨晚尤雨溪现场针对Vue3.0 Beta版本新特性知识点汇总

【新消息】Vue 3.0 Beta 版本发布,你还学的动么?

Vue真是太好了 壹万多字的Vue知识点 超详细!

Vue + Koa从零打造一个H5页面可视化编辑器——Quark-h5

深入浅出Vue3 跟着尤雨溪学 TypeScript 之 Ref 【实践】

手把手教你深入浅出vue-cli3升级vue-cli4的方法

Vue 3.0 Beta 和React 开发者分别杠上了

手把手教你用vue drag chart 实现一个可以拖动 / 缩放的图表组件

Vue3 尝鲜

总结Vue组件的通信

Vue 开源项目 TOP45

2020 年,Vue 受欢迎程度是否会超过 React?

尤雨溪:Vue 3.0的设计原则

使用vue实现HTML页面生成图片

实现全栈收银系统(Node+Vue)(上)

实现全栈收银系统(Node+Vue)(下)

vue引入原生高德地图

Vue合理配置WebSocket并实现群聊

多年vue项目实战经验汇总

vue之将echart封装为组件

基于 Vue 的两层吸顶踩坑总结

Vue插件总结【前端开发必备】

Vue 开发必须知道的 36 个技巧【近1W字】

构建大型 Vue.js 项目的10条建议

深入理解vue中的slot与slot-scope

手把手教你Vue解析pdf(base64)转图片【实践】

使用vue+node搭建前端异常监控系统

推荐 8 个漂亮的 vue.js 进度条组件

基于Vue实现拖拽升级(九宫格拖拽)

手摸手,带你用vue撸后台 系列二(登录权限篇)

手摸手,带你用vue撸后台 系列三(实战篇)

前端框架用vue还是react?清晰对比两者差异

Vue组件间通信几种方式,你用哪种?【实践】

浅析 React / Vue 跨端渲染原理与实现

10个Vue开发技巧助力成为更好的工程师

手把手教你Vue之父子组件间通信实践讲解【props、$ref 、$emit】

1W字长文+多图,带你了解vue的双向数据绑定源码实现

深入浅出Vue3 的响应式和以前的区别到底在哪里?【实践】

干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)

基于Vue/VueRouter/Vuex/Axios登录路由和接口级拦截原理与实现

手把手教你D3.js 实现数据可视化极速上手到Vue应用

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【上】

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【中】

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【下】

Vue3.0权限管理实现流程【实践】

后台管理系统,前端Vue根据角色动态设置菜单栏和路由

作者: 子君

转发链接:https://mp.weixin.qq.com/s/p4J9vqDD7-7FFK5tq_CZMA

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表