【愣锤笔记】基于vue的进阶散点干货
发布日期:2021-08-13 07:44:58 浏览次数:5 分类:技术文章

本文共 7040 字,大约阅读时间需要 23 分钟。

vue的开发如日中天,越来越多的开发者投入了vue开发大军中。希望本文中的一些vue散点,能在实际项目中灵活运用,切实地为我们解决一些难点问题。

插槽

// 组件调用时使用插槽
// todo-list-item组件的定义
  • // name定义插槽名 // :checked="checked"通过bind属性的方法,使得父组件在使用插槽时可以读取到现在分发出去的数,例如这样父组件就可以读取到这个分发出的checked值
  • 复制代码

    注意点:

    • 父组件的作用域是父组件的,如果想获取自组件的插槽数据,则需要自组件的插件将数据分发出去
    • 2.6版本之后绑定插槽名称,只能在template模板上,v-slot:插槽名,v-slot:theNameOfSlot="theSlotProps"属性值为slot分发给父组件的数据

    依赖注入

    // 在一个组件上设置注入的属性,可以是对象,也可以是函数返回一个对象provide: {    parentProvide: {      msg: 'hello world'    }},// 在其任意层级的子节点可以获取到父节点注入的属性inject: [    'parentProvide']复制代码

    依赖注入的属性是无法修改的,如果需要在祖孙组件中监听注入的属性变化,需要在祖宗组件中的注入属性为this, 即把祖宗属性作为注入属性往下传递。

    // 注意这里注入时使用的是函数返回的对象provide () {    return {      parentProvide: this    }},// 接收注入的属性并可以直接修改,修改后祖宗的这个属性值也会变化inject: [    'parentProvide'  ],methods: {    updataParentMsg () {      this.parentProvide.msg = '重置了'    }},复制代码

    依赖注入很好的解决了在跨层级组件直接的通信问题,在封装高级组件的时候会很常用。

    实现简易的vuex

    // 封装import Vue from 'vue'const Store = function (options = {}) {  const {state = {}, mutations = {}} = options  this._vm = new Vue({    data: {      $$state: state    }  })  this._mutations = mutations}Store.prototype.commit = function (type, payload) {  if (this._mutations[type]) {    this._mutations[type](this.state, payload)  }}Object.defineProperties(Store.prototype, {  state: {    get () {      return this._vm._data.$$state    }  }})export default { Store }// main.js,使用// 首先导入我们封装的vueximport Vuex from './min-store/index'// 简易挂载Vue.prototype.$store = new Vuex.Store({  state: {    count: 1  },  getters: {    getterCount: state => state.count  },  mutations: {    updateCount (state) {      state.count ++    }  }})// 页面使用computed: {    count () {      return this.$store.state.count    }  },  methods: {    addCount () {      this.$store.commit('updateCount')    }},复制代码

    vuex-getter的注意点

    // getter第一个参数是state,第二个参数是其他getters,模块中的getter第三个参数是根状态const getters = {  count: state => state.count,    // 例如可以返回getters.count * 2  otherCount: (state, getters) => getters.count * 2,    // 跟状态  otherCount: (state, getters, rootState) => rootState.someState,}// 辅助函数import { mapGetters } from 'vuex'computed: {    ...mapGetters([        'count',        'otherCount'    ])},// 模块加命名空间之后,car是当前getter所在的文件名// 如果父级也有命名空间,则需要加上父级的命名空间,例如`parentName/car`:computed: {    ...mapGetters('car', [        'count',        'otherCount'    ])},// 如果mapGetters中的值来自于多个模块,可以用对象的形式分别定义:...mapGetters({    'count': 'car/count',    'otherCount': 'car/otherCount',    'userName': 'account/userName'})// 也可以写多个mapGetterscomputed: {    ...mapGetters('account', {          'userName': 'userName'    }),    ...mapGetters('car', [      'count',      'otherCount'    ])}复制代码

    mapGetter的参数用数组的形式,书写更简洁方便,但是在需要重新命名getters等情况下则无法实现,此时可以换成对象的书写方式。

    vuex-mutations注意点

    推荐使用常量替代 mutation 事件类型:在store文件夹中新建mutation-types.js文件,将所有的mutation事件类型以常量的形式定义好。

    // mutation-types.jsexport const SOME_MUTATION = 'SOME_MUTATION'// 引用时,通过es6的计算属性命名的方式引入事件类型import * as types from '../mutation-types'const mutations = {  [types.UPDATE_USERINFO] (state, userInfo) {    state.count = userInfo  }}// 使用mapMutationsimport { mapMutations } from 'vuex'// 常量+命名空间的mutation貌似没法通过像mapGetters的一样用法,只能通过this.$store.commit的方式提交。this[`account/${types.UPDATE_USERINFO}`]('xiaoming')// 所以个人觉得这种情况,还是用action去触发mutation复制代码

    常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然

    vetur

    生成简易vue模板的快捷键:scaffold

    灵活的路由配置

    import Vue from 'vue'import Router from 'vue-router'Vue.use(Router)export default new Router({  mode: 'history',  routes: [    {      path: '/user',      title: '个人中心',      component: { render: h => h('router-view') },      children: [        {          path: '/user/index',          name: 'user-dashboard',          title: '个人中心',          meta: {            // 其他meta信息          },          component: () =>            import(/* webpackChunkName: user */ '@/views/dashboard/index')        },        {          path: '/user/car',          name: 'user-car',          title: '我的汽车',          meta: {            // 其他meta信息          },          component: () =>            import(/* webpackChunkName: user */ '@/views/car/index')        }      ]    }  ]})复制代码
    • () => import() 自动代码分割的异步组件
    • () => import(/* webpackChunkName: user */ '@/views/dashboard/index') 将文件打包到一个模块,例如这里的写法可以将dashboard的index打包到user模块中
    • render: h => h('router-view') 可以用render函数灵活的创建user模块的入口文件,省去了入口文件的编写。

    spa中的页面刷新

    spa应用的刷新我们不能采取reload的方式。所以需要另辟蹊径。

    方案一:当路由当query部分变化时,配router-view的key属性,路由是会重新刷新的。

    this.$router.replace({ path: this.$route.fullPath, query: { timestamp: Date.now() }})复制代码

    此种方法的弊端是url无缘无故多了一个参数,不是很好看。

    方案二:新建一个redirect空页面,刷新就从当前页面跳转到redirect页面,然后在redirect页面理解replace跳转回来。

    // redirect页面// 跳转方法,我们可以封装在utils公共函数中// 在utils/index.js文件中:import router from '../router'/** * 刷新当前路由 */export const refreshCurrentRoute = () => {  const { fullPath } = router.currentRoute  router.replace({    name: 'redirect',    params: {      redirect: fullPath    }  })}复制代码

    自定义指令实现最细粒度的权限控制(组件/元素级别的)

    为了扩展,我们在src下新建directives指令文件夹,然后新建index.js、account.js

    src/directives/index.js:

    import account from './account'const directives = [  account]const install = Vue => directives.forEach(e => e(Vue))export default { install }复制代码

    src/directives/account.js

    import { checkAuthorization } from '../utils/index'/** * 导出和权限相关的自定义指令 */export default Vue => {  /**   * 自定义权限指令   * @description 当用户有权限才显示当前元素   */  Vue.directive('auth', {    inserted (el, binding) {      if (!checkAuthorization(binding.value)) {        el.parentNode && el.parentNode.removeChild(el)      }    }  })}复制代码

    最后简单附上工具函数,具体的根据项目实际情况而定:

    /** * 检测用户是否拥有当前的权限 * @param { Array } auth 待检查的权限 */export const checkAuthorization = (auth = []) => {  if (!Array.isArray(auth)) {    throw TypeError('请检查参数类型:Excepted Array,got ' + Object.prototype.toString.call(auth).slice(8, -1))  }  return store.state.account.authorization.some(e => auth.includes(e))}复制代码

    自定义权限组件实现最细粒度的权限控制(组件/元素级别的)

    // 自定义权限组件// main.js中注册为全局组件import globalAuth from './components/authorization'Vue.component('global-auth', globalAuth)// 使用
    asdasdas
    复制代码

    监听某个元素的尺寸变化,例如div

    // 安装resize-detectorcnpm i --save resize-detector// 引入import { addListener, removeListener } from 'resize-detector'// 使用addListener(this.$refs['dashboard'], this.resize) // 监听removeListener(this.$refs['dashboard'], this.resize) // 取消监听// 一般我们会对回调函数进行去抖methods: {    // 这里用了lodash的debounce    resize: _.debounce(function (e) {      console.log('123')    }, 200)}复制代码

    提升编译速度

    可以通过在本地环境使用同步加载组件,生产环境异步加载组件

    // 安装插件cnpm i babel-plugin-dynamic-import-node --save-dev// .bablerc文件的dev增加配置"env": {    // 新增插件配置    "development": {      "plugins": ["dynamic-import-node"]    }    // 其他的内容    ……}// 然后路由文件的引入依旧可以使用之前的异步加载的方式component: () => import('xxx/xxx')// 通过注释可以使多个模块打包到一起component: () => import(/* user */ 'xxx/xxx')复制代码

    该方式修改本地环境和生产环境的文件加载方式,对代码的侵入性最小,在不需要的时候直接删去.bablerc文件中的配置就好,而不需要修改文件代码

    参考

    1.《Vue开发实战》视频,作者:唐金州 地址:

    2. D2admin基于vue的中后台框架,

    END

    百尺竿头、日进一步

    我是愣锤,一名前端爱好者
    欢迎交流、批评

    转载于:https://juejin.im/post/5cf3578af265da1ba431d656

    转载地址:https://blog.csdn.net/weixin_30679823/article/details/100091825 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

    上一篇:【前端基础】Web与Native交互之The JSBridge FAQ
    下一篇:spring boot admin 自定义

    发表评论

    最新留言

    哈哈,博客排版真的漂亮呢~
    [***.90.31.176]2024年04月15日 12时50分54秒