Henry Henry
  • JavaScript
  • TypeScript
  • Vue
  • ElementUI
  • React
  • HTML
  • CSS
  • 技术文档
  • GitHub 技巧
  • Nodejs
  • Chrome
  • VSCode
  • Other
  • Mac
  • Windows
  • Linux
  • Vim
  • VSCode
  • Chrome
  • iTerm
  • Mac
  • Obsidian
  • lazygit
  • Vim 技巧
  • 分类
  • 标签
  • 归档
  • 网站
  • 资源
  • Vue 资源
GitHub (opens new window)

Henry

小学生中的前端大佬
  • JavaScript
  • TypeScript
  • Vue
  • ElementUI
  • React
  • HTML
  • CSS
  • 技术文档
  • GitHub 技巧
  • Nodejs
  • Chrome
  • VSCode
  • Other
  • Mac
  • Windows
  • Linux
  • Vim
  • VSCode
  • Chrome
  • iTerm
  • Mac
  • Obsidian
  • lazygit
  • Vim 技巧
  • 分类
  • 标签
  • 归档
  • 网站
  • 资源
  • Vue 资源
GitHub (opens new window)
  • JavaScript

  • TypeScript

  • Vue

    • Vue 编码指南
    • vue-cli 启动本地服务局域网不能访问的原因分析
    • 解决 Vue 相同路由参数不同不会刷新的问题
    • 解决 vuex requires a Promise polyfill in this browser 问题
    • 关于父组件通过 v-on 接收子组件多个参数的一点研究
    • Vue $attrs 和 $listeners
    • Vue axios 发送 Form Data 数据格式请求
    • Vue 开发技巧
      • 路由参数解耦
      • 函数式组件
      • watch
        • 触发 watch 监听执行多个方法
        • watch 监听多个变量
      • 程序化的事件侦听器
      • 外部监听生命周期函数
      • 小项目使用 Vue.observable 替换 Vuex
        • 创建 store
        • 在组件中引用
      • api 代理
    • Vue 动态路由
    • Vue 集成 UEditor 富文本编辑器
    • Vue 修饰符
    • Vue 问题集合
    • Vue props 传多值的问题
    • vue-router 在 IE11 下手动更改 URL 的 hash 不会触发路由
    • vue-router 路由参数刷新消失的问题
    • 那些年被我们忽略的 vue 语法
    • vue 生命周期深入
    • vue 组件通信深入
    • vue 组件通信深入 Vuex
    • vue项目移动端、pc端适配方案
    • vuepress 如何引入 vuex
  • ElementUI

  • React

  • AntD

  • 前端
  • Vue
Henry
2020-08-04
目录

Vue 开发技巧

记录一下开发中使用的 vue 技巧

# 路由参数解耦

一般在组件内使用路由参数, 大多数人会这样做:

export default {
  methods: {
    getParamsId() {
      return this.$route.params.id
    }
  }
}
1
2
3
4
5
6
7

在组件中使用 $route 会使之与其对应路由形成高度耦合, 从而使组件只能在某些特定的 URL 上使用, 限制了其灵活性.

正确的做法是通过 props 解耦

const router = new VueRouter({
  routes: [
    {
      path: '/user/:id',
      component: User,
      props: true
    }
  ]
})
1
2
3
4
5
6
7
8
9

将路由的 props 属性设置为 true 后, 组件内可通过 props 接收到 params 参数

export default {
  props: ['id'],
  methods: {
    getParamsId() {
      return this.id
    }
  }
}
1
2
3
4
5
6
7
8

另外你还可以通过函数模式来返回 props

const router = new VueRouter({
  routes: [
    {
      path: '/user/:id',
      component: User,
      props: route => ({
        id: route.query.id
      })
    }
  ]
})
1
2
3
4
5
6
7
8
9
10
11

文档: 路由组件传参 | Vue Router (opens new window)

# 函数式组件

函数式组件是无状态, 它无法实例化, 没有任何的生命周期和方法. 创建函数式组件也很简单, 只需要在模板添加 functional 声明即可. 一般适合只依赖于外部数据的变化而变化的组件, 因其轻量, 渲染性能也会有所提高.

组件需要的一切都是通过 context 参数传递. 它是一个上下文对象, 具体属性查看文档. 这里 props 是一个包含所有绑定属性的对象.

函数式组件

<template functional>
  <div class="list">
    <div class="item" v-for="item in props.list" :key="item.id" @click="props.itemClick(item)">
      <p>{{item.title}}</p>
      <p>{{item.content}}</p>
    </div>
  </div>
</template>
1
2
3
4
5
6
7
8

父组件使用

<template>
  <div>
    <List :list="list" :itemClick="item => (currentItem = item)"></List>
  </div>
</template>
1
2
3
4
5
import List from '@/components/List.vue'
export default {
  components: {
    List
  },
  data() {
    return {
      list: [
        {
          title: 'title',
          content: 'content'
        }
      ],
      currentItem: ''
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

文档: 函数式组件 (opens new window)

# watch

# 触发 watch 监听执行多个方法

使用数组可以设置多项, 形式包括字符串、函数、对象

export default {
  data: {
    name: 'Joe'
  },
  watch: {
    name: [
      'sayName1',
      function(newVal, oldVal) {
        this.sayName2()
      },
      {
        handler: 'sayName3',
        immediate: true
      }
    ]
  },
  methods: {
    sayName1() {
      console.log('sayName1==>', this.name)
    },
    sayName2() {
      console.log('sayName2==>', this.name)
    },
    sayName3() {
      console.log('sayName3==>', this.name)
    }
  }
}
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

# watch 监听多个变量

watch 本身无法监听多个变量. 但我们可以将需要监听的多个变量通过计算属性返回对象, 再监听这个对象来实现 "监听多个变量"

export default {
  data() {
    return {
      msg1: 'apple',
      msg2: 'banana'
    }
  },
  computed: {
    msgObj() {
      const { msg1, msg2 } = this
      return {
        msg1,
        msg2
      }
    }
  },
  watch: {
    msgObj: {
      handler(newVal, oldVal) {
        if (newVal.msg1 != oldVal.msg1) {
          console.log('msg1 is change')
        }
        if (newVal.msg2 != oldVal.msg2) {
          console.log('msg2 is change')
        }
      },
      deep: true
    }
  }
}
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

文档: watch (opens new window)

# 程序化的事件侦听器

比如, 在页面挂载时定义计时器, 需要在页面销毁时清除定时器. 这看起来没什么问题. 但仔细一看 this.timer 唯一的作用只是为了能够在 beforeDestroy 内取到计时器序号, 除此之外没有任何用处.

export default {
  mounted() {
    this.timer = setInterval(() => {
      console.log(Date.now())
    }, 1000)
  },
  beforeDestroy() {
    clearInterval(this.timer)
  }
}
1
2
3
4
5
6
7
8
9
10

如果可以的话最好只有生命周期钩子可以访问到它. 这并不算严重的问题, 但是它可以被视为杂物.

我们可以通过 $on 或 $once 监听页面生命周期销毁来解决这个问题:

export default {
  mounted() {
    this.createInterval('hello')
    this.createInterval('world')
  },
  createInterval(msg) {
    let timer = setInterval(() => {
      console.log(msg)
    }, 1000)
    this.$once('hook:beforeDestroy', function() {
      clearInterval(timer)
    })
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

使用这个方法后, 即使我们同时创建多个计时器, 也不影响效果. 因为它们会在页面销毁后程序化的自主清除.

文档: 程序化的事件侦听器 (opens new window)

# 外部监听生命周期函数

当我们使用一个第三方组件时, 可能需要监听组件数据的变化, 但是组件又没有提供 change 事件, 那我们怎么在外部监听组件的 updated 的变化呢?

<template>
  <!--通过 @hook:updated 监听组件的 updated 生命钩子函数-->
  <!--组件的所有生命周期钩子都可以通过 @hook:钩子函数名 来监听触发-->
  <custom-select @hook:updated="$_handleSelectUpdated" />
</template>
<script>
  import CustomSelect from 'custom-select'
  export default {
    components: {
      CustomSelect
    },
    methods: {
      $_handleSelectUpdated() {
        console.log('custom-select 组件的 updated 钩子函数被触发')
      }
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 小项目使用 Vue.observable 替换 Vuex

在前端项目中, 有许多数据需要在各个组件之间进行传递共享, 这时候就需要有一个状态管理工具, 一般情况下, 我们都会使用 Vuex , 但对于小型项目来说, 就像 Vuex 官网所说: "如果您不打算开发大型单页应用, 使用 Vuex 可能是繁琐冗余的. 确实是如此------如果您的应用够简单, 您最好不要使用 Vuex". 这时候我们就可以使用 Vue2.6 提供的新 API  Vue.observable 手动打造一个 Vuex

# 创建 store

import Vue from 'vue'

// 通过 Vue.observable 创建一个可响应的对象
export const store = Vue.observable({
  userInfo: {},
  roleIds: []
})

// 定义 mutations, 修改属性
export const mutations = {
  setUserInfo(userInfo) {
    store.userInfo = userInfo
  },
  setRoleIds(roleIds) {
    store.roleIds = roleIds
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 在组件中引用

<template>
  <div>
    {{ userInfo.name }}
  </div>
</template>
<script>
  import { store, mutations } from 'store'
  export default {
    computed: {
      userInfo() {
        return store.userInfo
      }
    },
    created() {
      mutations.setUserInfo({
        name: 'Henry'
      })
    }
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# api 代理

一般我们都需要在开发环境中设置代理来避免跨域问题, 类似下面这种:

proxyTable: {
  // 用 '/api' 开头, 代理所有请求到目标服务器
  '/api': {
    target: 'https://xxx.com', // 接口域名
    changeOrigin: true // 是否启用跨域
  }
}
1
2
3
4
5
6
7

一般项目都是 /api 开头的请求, 但也有项目有多个不同开头的请求, 如 /base, /user; 但我们也不能在代理中把这些都写一遍

但我们可以更改 axios 的默认配置 axios.defaults.baseURL = '/api', 再在代理中利用路径改写来将 /api 替换为空即可

proxyTable: {
  // 用 '/api' 开头, 代理所有请求到目标服务器
  '/api': {
    target: 'https://xxx.com', // 接口域名
    changeOrigin: true, // 是否启用跨域
    pathRewrite: { // 路径改写
      '^/api': ''
    }
  }
}
1
2
3
4
5
6
7
8
9
10
编辑 (opens new window)
#Vue
上次更新: 5/27/2023, 1:02:05 PM
Vue axios 发送 Form Data 数据格式请求
Vue 动态路由

← Vue axios 发送 Form Data 数据格式请求 Vue 动态路由→

最近更新
01
version 1.15
07-01
02
version 1.14
06-27
03
version 1.13
06-27
更多文章>
Theme by Vdoing | Copyright © 2017-2023 HenryTSZ | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式