Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue 知识点及问题汇总 #7

Open
kangkai124 opened this issue Feb 27, 2019 · 6 comments
Open

vue 知识点及问题汇总 #7

kangkai124 opened this issue Feb 27, 2019 · 6 comments
Labels
Solution 解决问题的一些方案 Vue

Comments

@kangkai124
Copy link
Owner

关于vue

@kangkai124
Copy link
Owner Author

模拟已废弃 vue 1.x 的 $dispatch$broadcast 方法

实现以下功能:

  • 在子组件调用 dispatch 方法,向上级指定的组件实例(最近的)上触发自定义事件,并传递数据,且该上级组件已预先通过 $on 监听了这个事件;
  • 相反,在父组件调用 broadcast 方法,向下级指定的组件实例(最近的)上触发自定义事件,并传递数据,且该下级组件已预先通过 $on 监听了这个事件。
function broadcast(componentName, eventName, params) {
    this.$children.forEach(child => {
        const name = child.$options.name;

        if (name === componentName) {
            child.$emit.apply(child, [eventName].concat(params));
        } else {
            // todo 如果 params 是空数组,接收到的会是 undefined
            broadcast.apply(child, [componentName, eventName].concat([params]));
        }
    });
}
export default {
    methods: {
        dispatch(componentName, eventName, params) {
            let parent = this.$parent || this.$root;
            let name = parent.$options.name;

            while (parent && (!name || name !== componentName)) {
                parent = parent.$parent;

                if (parent) {
                    name = parent.$options.name;
                }
            }
            if (parent) {
                parent.$emit.apply(parent, [eventName].concat(params));
            }
        },
        broadcast(componentName, eventName, params) {
            broadcast.call(this, componentName, eventName, params);
        }
    }
};

@kangkai124
Copy link
Owner Author

kangkai124 commented Mar 28, 2019

vue 组件使用 v-model

父组件

<template>
  <div>
    <Child v-model="list" />
  </div>
</template>
<script>
import Child from './Child'

export default {
  name: 'Parent',
  component: { Child },
  data () { return { list: [1,2,3] } }
}
</script>

子组件

<template>
  <div class="child" @click="newList">
    <img v-for="item in list" />
  </div>
</template>
<script>
export default {
  name: 'Child',
  model: {
    prop: 'list',
    event: 'new'
  },
  methods: {
    newList () {
      this.$emit('new', [4, 5, 6])
    }
  }
}
</script>

@kangkai124
Copy link
Owner Author

computed 属性绑定过程

如官方给的例子

var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})
  1. data 属性初始化 getter, setter
  2. computed 计算属性初始化,接受的函数作为 vm.reversedMessage 的 getter
  3. 首次获取 reversedMessage 的值时,Dep 开始依赖收集
  4. 在执行 message getter 方法时,如果 Dep 处于依赖收集状态,则判定 message 为 reversedMessage 的依赖,建立依赖关系
  5. message 发生变化时,根据依赖关系,触发 reversedMessage 重新计算

@kangkai124
Copy link
Owner Author

ivew 组件 Tabs 第一次切换标签内部 Table 卡顿问题

从折线图切换到到表格时,表格会卡顿一下。
WX20190411-102606@2x

<Tabs>
        <TabPane label="折线图" name="line-chart">
          <SimpleChart :data="data" />
        </TabPane>
        <TabPane label="表格" name="table">
          <SimpleGrid :data="data" :columns="columns" />
        </TabPane>
      </Tabs>

分析:进到 Modal 时,折线图和表格组件都已经渲染,但此时表格的 TabPane display:none,Table 获取不到宽高,所以渲染出来的数据堆在一条线上。当切换到表格时,display:block,Table 获取宽高撑开盒子,所以有了一瞬间的卡顿。

解决方法:使用 this.$nextTick 控制表格延迟渲染

<Tabs @on-click="onTabClick">
        <TabPane label="折线图" name="line-chart">
          <SimpleChart :data="data" />
        </TabPane>
        <TabPane label="表格" name="table">
          <SimpleGrid :data="data" :columns="columns" v-if="mount" />
        </TabPane>
      </Tabs>
export default {
    ...
    data () {
        return {
          mount: false
        }
    },
    methods: {
        onTabClick (name) {
            if (name === 'table') {
                this.$nextTick(() => {
                    this.clickTable = true
                })
            }
        }
    }
    ...
}

@kangkai124 kangkai124 changed the title vue vue 知识点及问题汇总 Apr 12, 2019
@kangkai124
Copy link
Owner Author

Uncaught TypeError: timeout.close is not a function

使用了定时器,然后在 beforeDestory 里清除定时器:

  beforeDestroy () {
    if (this.timer) {
      clearInterval(this.timer)
      this.timer = null
    }
  },

但是浏览器提示有错误:

image

最后,,,发现是 vs code 自动给我加了段引用代码!!

import { clearInterval } from 'timers'

只要把上面那行代码删了就阔以了。

@kangkai124 kangkai124 added Vue Solution 解决问题的一些方案 labels May 7, 2019
@kangkai124
Copy link
Owner Author

程序化的事件侦听器

例如,你可能经常看到这种集成一个第三方库的模式:

// 一次性将这个日期选择器附加到一个输入框上
// 它会被挂载到 DOM 上。
mounted: function () {
  // Pikaday 是一个第三方日期选择器的库
  this.picker = new Pikaday({
    field: this.$refs.input,
    format: 'YYYY-MM-DD'
  })
},
// 在组件被销毁之前,
// 也销毁这个日期选择器。
beforeDestroy: function () {
  this.picker.destroy()
}

这里有两个潜在的问题:

  • 它需要在这个组件实例中保存这个 picker,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。
  • 我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化地清理我们建立的所有东西。

你应该通过一个程序化的侦听器解决这两个问题:

mounted: function () {
  var picker = new Pikaday({
    field: this.$refs.input,
    format: 'YYYY-MM-DD'
  })

  this.$once('hook:beforeDestroy', function () {
    picker.destroy()
  })
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Solution 解决问题的一些方案 Vue
Projects
None yet
Development

No branches or pull requests

1 participant