分享Vue项目中会用到的一些实战技巧点

酷涛吖_7413

酷涛吖_7413

2020-09-28

2747人浏览

转载

在开发Vue的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天小编就整理了几个在项目中会用到的一些实战技巧点,希望可以帮助到正在努力赚钱的你。江湖规矩,先赞后看,艳遇不断。

数据不响应,可能是用法有问题

前几天有朋友给我发了一段代码,然后说Vue有bug,他明明写的没问题,为啥数据就不响应呢,一定是Vue的bug?我感觉他比尤雨溪要牛逼,高攀不起,就没有理他了。但是确实有时候我们在开发时候会遇到数据不响应的情况,那怎么办呢?比如下面这段代码:

<template>
  <div>
    <div>
      <span>用户名: {{ userInfo.name }}</span>
      <span>用户性别: {{ userInfo.sex }}</span>
      <span>
        公众号: {{ userInfo.officialAccount }}
      </span>
    </div>
    <button>添加公众号</button>
  </div>
</template><script>
export default {
  data() {
    return {
      userInfo: {
        name: '子君',
        sex: '男'
      }
    }
  },
  methods: {
    // 在这里添加用户的公众号
    handleAddOfficialAccount() {
      this.userInfo.officialAccount = '前端有的玩'
    }
  }
}
</script>

在上面的代码中,我们希望给用户信息里面添加公众号属性,但是通过this.userInfo.officialAccount = '前端有的玩' 添加之后,并没有生效,这是为什么呢?

这是因为在Vue内部,数据响应是通过使用Object.definePrototype监听对象的每一个键的getter,setter方法来实现的,但通过这种方法只能监听到已有属性,新增的属性是无法监听到的,但我就是想监听,小编你说咋办吧。下面小编提供了四种方式,如果有更多方式,欢迎下方评论区告诉我。

1. 将本来要新增的属性提前在Vue0中定义好

比如上面的公众号,我可以提前在Vue1里面定义好,这样就不是新增属性了,就像下面这样

data() {
    return {
      userInfo: {
        name: '子君',
        sex: '男',
        // 我先提前定义好
        officialAccount: ''
      }
    }
  }

2. 直接替换掉Vue2

虽然无法给Vue1里面添加新的属性,但是因为Vue1已经定义好了,所以我直接修改Vue1的值不就可以了么,所以也可以像下面这样写

this.userInfo = {
  // 将原来的userInfo 通过扩展运算法复制到新的对象里面
  ...this.userInfo,
  // 添加新属性
  officialAccount: '前端有的玩'
}

3. 使用Vue6

其实上面两种方法都有点取巧的嫌疑,其实对于新增属性,Vue官方专门提供了一个新的方法Vue8用来解决新增属性无法触发数据响应。

Vue.set 方法定义

/**
* target 要修改的对象
* prpertyName 要添加的属性名称
* value 要添加的属性值
*/
Vue.set( target, propertyName, value )

上面的代码使用Vue8可以修改为

import Vue from 'vue'

// 在这里添加用户的公众号
handleAddOfficialAccount() {
  Vue.set(this.userInfo,'officialAccount', '前端有的玩')
}

但是每次要用到bug0方法的时候,还要把Vue引入进来,好麻烦,所以为了简便起见,Vue又将bug0方法挂载到了Vue的原型链上了,即Vue.prototype.$set = Vue.set,所以在Vue组件内部可以直接使用bug6代替Vue8

this.$set(this.userInfo,'officialAccount', '前端有的玩')

小编发现有许多同学不知道什么时候应该用Vue8,其实只有当你要赋值的属性还没有定义的时候需要使用bug9,其他时候一般不会需要使用。

4. 使用Vue0

我觉得$forceUpdate的存在,让许多前端开发者不会再去注意数据双向绑定的原理,因为不论什么时候,反正我修改了Vue1之后,调用一下Vue2就会让Vue组件重新渲染,bug是不会存在的。但是实际上这个方法并不建议使用,因为它会引起许多不必要的性能消耗。

针对数组的特定方式

其实不仅仅是对象,数组也存在数据修改之后不响应的情况,比如下面这段代码

<template>
  <div>
    <ul>
      <li>
        {{ item }}
      </li>
    </ul>
    <button>修改名称</button>
  </div>
</template><script>
export default {
  data() {
    return {
      list: ['张三', '李四']
    }
  },
  methods: {
    // 修改用户名称
    handleChangeName() {
      this.list[0] = '王五'
    }
  }
}
</script>

上面的代码希望将张三的名字修改为王五,实际上这个修改并不能生效,这是因为Vue不能检测到以下变动的数组:

  • 当你利用索引直接设置一个项时,例如: Vue6

  • 修改数组的Vue7属性,例如: Vue8

所以在上例中通过Vue9 是无法触发数据响应的,那应该怎么办呢?像上面提到的Vue8和Vue2都可以解决这个问题,比如Vue8可以这样写

Vue.set(this.list,0,'王五')

除了那些方法之外,Vue还针对数组提供了变异方法

在操作数组的时候,我们一般会用到数据提供的许多方法,比如bug4,bug5,bug6等等,在Vue中调用数组上面提供的这些方法修改数组的值是可以触发数据响应的,比如上面的代码改为以下代码即可触发数据响应

this.list.splice(0,1,'王五')

实际上,如果Vue仅仅依赖getter与setter,是无法做到在数组调用bug4,bug5等方法时候触发数据响应的,因此Vue实际上是通过劫持这些方法,对这些方法进行包装变异来实现的。

Vue对数组的以下方法进行的包装变异:

  • push
  • pop
  • shift
  • unshift
  • splice
  • sort
  • reverse

所以在操作数组的时候,调用上面这些方法是可以保证数据可以正常响应,下面是Vue源码中包装数组方法的代码:

var original = arrayProto[method];
  def(arrayMethods, method, function mutator () {
    // 将 arguments 转换为数组
    var args = [], len = arguments.length;
    while ( len-- ) args[ len ] = arguments[ len ];
    var result = original.apply(this, args);
    // 这儿的用法同dependArray(value),就是为了取得dep
    var ob = this.__ob__;
    var inserted;
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args;
        break
      case 'splice':
        inserted = args.slice(2);
        break
    }
    // 如果有新的数据插入,则插入的数据也要进行一个响应式
    if (inserted) { ob.observeArray(inserted); }
   // 通知依赖进行更新
    ob.dep.notify();
    return result
  });

文本格式化,this.userInfo.officialAccount = '前端有的玩'6更简单

使用this.userInfo.officialAccount = '前端有的玩'6 简化逻辑

我想把时间戳显示成this.userInfo.officialAccount = '前端有的玩'8的格式怎么办?是需要在代码中先将日期格式化之后,再渲染到模板吗?就像下面这样

<template>
  <div>
    {{ dateStr }}
    <ul>
      <li>
        {{ item.date }}
      </li>
    </ul>
  </div>
</template><script>
import { format } from '@/utils/date'
export default {
  data() {
    return {
      date: Date.now(),
      list: [
        {
          date: Date.now()
        }
      ]
    }
  },
  computed: {
    dateStr() {
      return format(this.date, 'yyyy-MM-DD HH:mm:ss')
    },
    getList() {
      return this.list.map(item => {
        return {
          ...item,
          date: format(item.date, 'yyyy-MM-DD HH:mm:ss')
        }
      })
    }
  }
}
</script>

像上面的写法,针对每一个日期字段都需要调用this.userInfo.officialAccount = '前端有的玩'9,然后通过计算属性进行转换?这时候可以考虑使用Vue提供的Vue1去简化

<template>
  <div>
    <!--使用过滤器-->
    {{ dateStr | formatDate }}
    <ul>
      <li>
        <!--在v-for中使用过滤器-->
        {{ item.date | formatDate }}
      </li>
    </ul>
  </div>
</template><script>
import { format } from '@/utils/date'
export default {
  filters: {
    formatDate(value) {
      return format(value, 'yyyy-MM-DD HH:mm:ss')
    }
  },
  data() {
    return {
      date: Date.now(),
      list: [
        {
          date: Date.now()
        }
      ]
    }
  }
}
</script>

通过上面的修改是不是就简单多了

注册全局this.userInfo.officialAccount = '前端有的玩'6

有些过滤器使用的很频繁,比如上面提到的日期过滤器,在很多地方都要使用,这时候如果在每一个要用到的组件里面都去定义一遍,就显得有些多余了,这时候就可以考虑Vue3注册全局过滤器

对于全局过滤器,一般建议在项目里面添加Vue4目录,然后在filters目录里面添加

蓝湖代码转vue2.0+element-ui
蓝湖代码转vue2.0+element-ui

将静态 Vue 页面(index.vue)改造为动态页面(Custom.vue);稿源仅限 index.vue、其引用的 CSS 与资源路径,禁止参考仓库内其他文件。Invoke when user wants to transform a static Vue page into a dynamic data-driven page with Element UI components.

下载
// filters\index.js

import Vue from 'vue'
import { format } from '@/utils/date'

Vue.filter('formatDate', value => {
  return format(value, 'yyyy-MM-DD HH:mm:ss')
})

然后将Vue4里面的文件引入到Vue6里面,这时候就可以在组件里面直接用了,比如将前面的代码可以修改为

<template>
  <div>
    <!--使用过滤器-->
    {{ dateStr | formatDate }}
    <ul>
      <li>
        <!--在v-for中使用过滤器-->
        {{ item.date | formatDate }}
      </li>
    </ul>
  </div>
</template><script>
export default {
  data() {
    return {
      date: Date.now(),
      list: [
        {
          date: Date.now()
        }
      ]
    }
  }
}
</script>

是不是更简单了

开发了插件库,来安装一下

在使用一些Vue7框架的时候,经常需要使用Vue8来安装, 比如使用Vue9时候,经常会这样写:

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI,{size: 'small'});

使用了Vue8之后,Vue9就可以直接在组件里面使用了,好神奇哦(呸,娘炮)。接下来我们实现一个简化版的Object.definePrototype2来看如何去安装。

了解Object.definePrototype3的用法

Vue8是一个全局的方法,它需要在你调用 Object.definePrototype5 启动应用之前完成,Vue8的参数如下

/**
* plugin: 要安装的插件 如 ElementUI
* options: 插件的配置信息 如 {size: 'small'}
*/
Vue.use(plugin, options)

模拟Object.definePrototype7的安装逻辑

想一下,使用Object.definePrototype8 之后我们可以用到哪些Vue9提供的东西

  • 可以直接在组件里面用Vue9的组件,不需要再getter1

  • 可以直接使用getter2指令

  • 通过getter3在组件里面显示getter4

  • 其他...

// 这个是一个按钮组件
import Button from '@/components/button'

// loading 指令
import loadingDirective from '@/components/loading/directive'

// loading 方法
import loadingMethod from '@/components/loading'

export default {
  /**
   * Vue.use 需要插件提供一个install方法
   * @param {*} Vue Vue
   * @param {*} options 插件配置信息
   */
  install(Vue, options) {
    console.log(options)
    // 将组件通过Vue.components 进行注册
    Vue.components(Button.name, Button)

    // 注册全局指令
    Vue.directive('loading', loadingDirective)

    // 将loadingMethod 挂载到 Vue原型链上面,方便调用
    Vue.prototype.$loading = loadingMethod
  }
}

通过上面的代码,已经实现了一个丐版的Vue9插件,这时候就可以在Vue6里面通过Vue8进行插件安装了。大家可能会有疑问,为什么我要用这种写法,不用这种写法我照样可以实现功能啊。小编认为这种写法有两个优势

  • 标准化,通过提供一种统一的开发模式,无论对插件开发者还是使用者来说,都有一个规范去遵循。

  • 插件缓存,Vue8 在安装插件的时候,会对插件进行缓存,即一个插件如果安装多次,实际上只会在第一次安装时生效。

插件的应用场景

  • 添加全局方法或者 property。

  • 添加全局资源:指令/过滤器/过渡等。

  • 通过全局混入来添加一些组件选项。

  • 添加 Vue 实例方法,通过把它们添加到 getter9 上实现。

  • 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如Vue9

提高Vue渲染性能,了解一下Object.freeze

当一个 Vue 实例被创建时,它将 Vue1 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。但是这个过程实际上是比较消耗性能的,所以对于一些有大量数据但只是展示的界面来说,并不需要将setter2加入到响应式系统中,这样可以提高渲染性能,怎么做呢,你需要了解一下setter3。

在Vue官网中,有这样一段话:这里唯一的例外是使用 setter5,这会阻止修改现有的 property,也意味着响应系统无法再_追踪_变化。这段话的意思是,如果我们的数据使用了setter3,就可以让数据脱离响应式系统,那么该如何做呢?

比如下面这个表格,因为只是渲染数据,这时候我们就可以通过setter3来优化性能

<template>
  <el-table>
    <el-table-column></el-table-column>
    <el-table-column></el-table-column>
    <el-table-column></el-table-column>
  </el-table></template><script>
export default {
  data() {
    const data = Array(1000)
      .fill(1)
      .map((item, index) => {
        return {
          date: '2020-07-11',
          name: `子君${index}`,
          address: '大西安'
        }
      })
    return {
      // 在这里我们用了Object.freeze
      tableData: Object.freeze(data)
    }
  }
}
</script>

有的同学可能会有疑问,如果我这个表格的数据是滚动加载的,你这样写我不就没法再给setter8添加数据了吗?是,确实没办法去添加数据了,但还是有办法解决的,比如像下面这样

export default {
  data() {
    return {
      tableData: []
    }
  },
  created() {
    setInterval(() => {
      const data = Array(1000)
        .fill(1)
        .map((item, index) => {
          // 虽然不能冻结整个数组,但是可以冻结每一项数据
          return Object.freeze({
            date: '2020-07-11',
            name: `子君${index}`,
            address: '大西安'
          })
        })
      this.tableData = this.tableData.concat(data)
    }, 2000)
  }
}

合理的使用setter3,是可以节省不少渲染性能,特别对于IE浏览器,效果还是很明显的,赶快去试试吧。

最后如果你现在需要开发移动端项目,可以了解一下小编整理的一个开箱即用框架 Vue00,也许可以帮到你哦

结语

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

相关推荐:

Vue01

Vue02

更多编程相关知识,请访问:Vue03!!

前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

vue

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Tailwind CSS 响应式布局怎么写
Tailwind CSS 响应式布局怎么写

Tailwind CSS 响应式布局通常从移动端样式写起,再用 sm、md、lg 等前缀调整不同屏幕宽度下的网格、间距和导航。本专题整理断点配置、Grid 与 Flex 自适应布局及常见溢出问题,帮助你逐步完成多设备适配。

2026.11.03

0

19

Tailwind CSS 常用类名怎么记
Tailwind CSS 常用类名怎么记

Tailwind CSS 类名很多,先按布局、间距、文字、颜色和状态分组记忆,再通过官方文档检索具体写法。本专题结合类名排序、动态拼接失效、自定义实用类等问题,帮助你建立常用类名的速查方法。

2026.11.03

0

12

码上飞入口地址合集
码上飞入口地址合集

本专题汇总了码上飞(CodeFlying)的官方入口地址合集,涵盖官网主站及网页版在线使用入口,支持注册登录后直接在线体验零代码AI应用生成。同时整理了APP端下载渠道与小程序入口,助你快速访问平台,通过自然语言描述需求即可生成应用、小程序或网站。

2026.11.03

0

10

Uvicorn 报错与问题解决教程
Uvicorn 报错与问题解决教程

本专题汇总了Uvicorn服务器常见问题与报错解决的教程合集,涵盖启动失败、端口占用、模块导入错误、事件循环冲突及热重载失效等典型故障的排查思路。同时整理了多进程与Worker配置、SSL/HTTPS证书报错、跨域与代理配置等实战解决方案,助你快速定位并解决Uvicorn运行中的各类问题。

2026.11.02

20

14

Uvicorn使用教程
Uvicorn使用教程

本专题汇总了Uvicorn使用教程与启动运行指南,涵盖其作为Python ASGI服务器的定位与特点,以及命令行启动(uvicorn main:app --reload)、参数配置(host/port/workers)、程序内嵌运行与Gunicorn结合部署等核心用法。同时整理了热重载调试、日志配置与生产环境部署优化等技巧,助你快速掌握Uvicorn的运行与配置。

2026.11.02

20

17

Uvicorn安装配置教程
Uvicorn安装配置教程

本专题汇总了Uvicorn的安装配置教程与部署指南,涵盖通过pip安装Uvicorn、启动FastAPI/Starlette应用、开发模式热重载(--reload)及多进程工作模式配置等核心操作。同时整理了结合Gunicorn的生产部署方案、HTTPS与反向代理配置及性能调优技巧,助你快速完成Uvicorn服务的安装与上线部署。

2026.11.02

20

17

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

2026.10.28

120

16

Vite 如何搭配 Vue.js
Vite 如何搭配 Vue.js

Vite搭配Vue.js专题汇集创建Vue 3项目、配置开发环境、路径别名、Vue插件、代理、多环境构建与调试的已审核文章,帮助读者完成从初始化到日常开发的配置。

2026.10.28

100

15

Vite 项目目录怎么看
Vite 项目目录怎么看

Vite项目目录专题汇集入口文件、src源码、public静态资源、路径别名、项目根目录和构建输出目录相关的已审核文章,帮助读者理解各文件夹的用途与引用方式。

2026.10.28

300

10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
uni-app快速上手
uni-app快速上手

共0课时 | 0人学习

Vue 教程
Vue 教程

共42课时 | 17.4万人学习

Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 2.6万人学习