其它实用程序

TIP

有关UMD版本的使用,请参见此处.

打开外部URL

import { openURL } from 'quasar'

openURL('http://...')

// full syntax:
openURL(
  String url,
  Function rejectFn, // optional; gets called if window cannot be opened
  Object windowFeatures // (v1.13+) optional requested features for the new window
)

它将处理在Cordova、Electron或浏览器下运行时涉及的怪异行为,包括通知用户他/她必须确认打开弹出窗口。

当用Cordova(或Capacitor)包装时,如果InAppBrowserCordova插件还安装了那最好(但不是“必须做的”),这样openURL就可以挂接到这个插件中。

从Quasar v1.11+开始,如果运行在iOS并且cordova-plugin-safariviewcontroller安装了,则openURL将首先尝试挂接到它。

可选的windowFeatures参数应该是一个具有来自window.open()窗口功能的键和布尔值的对象(如下例所述)。请注意,当openURL不使用window.open()这种实现时,这些特性将不被考虑(例如,当它挂接在InAppBrowser或electron自己的窗口打开器时)。

// example of openURL() with windowFeatures:
// (requires Quasar v1.13+)

openURL(
  'http://...',
  null, // in this example we don't care about the rejectFn()

  // this is the windowFeatures Object param:
  {
    noopener: true, // this is set by default for security purposes
                    // but it can be disabled if specified with a Boolean false value
    menubar: true,
    toolbar: true,
    noreferrer: true,
    // .....any other window features
  }
)

TIP

如果要在Cordova应用程序中打开电话拨号器,请不要使用 openURL()。 相反,你应该直接使用 <a href="tel:123456789"> 标签或 <QBtn href="tel:123456789">

复制到剪贴板

以下是将一些文本复制到剪贴板的助手。 该方法返回一个Promise。

import { copyToClipboard } from 'quasar'

copyToClipboard('some text')
  .then(() => {
    // 成功!
  })
  .catch(() => {
    // 失败
  })

导出文件

以下是触发文件下载的助手。

import { exportFile } from 'quasar'

// mimeType是可选的;
// 默认的mimeType为“text/plain”
(status) exportFile(fileName, rawData[, mimeType])

最简单的例子:

import { exportFile } from 'quasar'

const status = exportFile('important.txt', 'Some important content')

if (status === true) {
  // 浏览器允许
}
else {
  // 浏览器拒绝
  console.log('Error: ' + status)
}

runSequentialPromises

下面是一个辅助程序,用于连续运行多个Promise。可以选择在多个线程上运行

/**
 * Run a list of Promises sequentially, optionally on multiple threads.
 *
 * @param {*} sequentialPromises - Array of Functions or Object with Functions as values
 *                          Array of Function form: [ (resultAggregator: Array) => Promise<any>, ... ]
 *                          Object form: { [key: string]: (resultAggregator: object) => Promise<any>, ... }
 * @param {*} opts - Optional options Object
 *                   Object form: { threadsNumber?: number, abortOnFail?: boolean }
 *                   Default: { threadsNumber: 1, abortOnFail: true }
 *                   When configuring threadsNumber AND using http requests, be
 *                       aware of the maximum threads that the hosting browser
 *                       supports (usually 5); any number of threads above that
 *                       won't add any real benefits
 * @returns Promise<Array<Object> | Object>
 *    With opts.abortOnFail set to true (which is default):
 *        When sequentialPromises param is Array:
 *          The Promise resolves with an Array of Objects of the following form:
 *             [ { key: number, status: 'fulfilled', value: any }, ... ]
 *          The Promise rejects with an Object of the following form:
 *             { key: number, status: 'rejected', reason: Error, resultAggregator: array }
 *        When sequentialPromises param is Object:
 *          The Promise resolves with an Object of the following form:
 *             { [key: string]: { key: string, status: 'fulfilled', value: any }, ... }
 *          The Promise rejects with an Object of the following form:
 *             { key: string, status: 'rejected', reason: Error, resultAggregator: object }
 *    With opts.abortOnFail set to false:
 *       The Promise is never rejected (no catch() needed)
 *       The Promise resolves with:
 *          An Array of Objects (when sequentialPromises param is also an Array) of the following form:
 *             [ { key: number, status: 'fulfilled', value: any } | { status: 'rejected', reason: Error }, ... ]
 *          An Object (when sequentialPromises param is also an Object) of the following form:
 *             { [key: string]: { key: string, status: 'fulfilled', value: any } | { key: string, status: 'rejected', reason: Error }, ... }
 */

请注意。

  • sequentialPromises参数是一个函数数组(每个函数返回一个Promise)。
  • sequentialPromises中的每个函数都收到一个参数,即resultAggregator,所以基本上你可以使用以前的承诺的结果来决定如何处理当前的Promise;resultAggregator中每个尚未解决的条目都被标记为null
  • opts参数是可选的。

通用的例子(将sequentialPromises参数设为数组)。

import { runSequentialPromises } from 'quasar'

runSequentialPromises([
  (resultAggregator) => new Promise((resolve, reject) => { /* do some work... */ }),
  (resultAggregator) => new Promise((resolve, reject) => { /* do some work... */ })
  // ...
]).then(resultAggregator => {
  // resultAggregator is ordered in the same way as the promises above
  console.log('result from first Promise:', resultAggregator[0].value)
  console.log('result from second Promise:', resultAggregator[1].value)
  // ...
}).catch(errResult => {
  console.error(`Error encountered on job #${ errResult.key }:`)
  console.error(errResult.reason)
  console.log('Managed to get these results before this error:')
  console.log(errResult.resultAggregator)
})

通用的例子(将sequentialPromises参数设为Object):

import { runSequentialPromises } from 'quasar'

runSequentialPromises({
  phones: (resultAggregator) => new Promise((resolve, reject) => { /* do some work... */ }),
  laptops: (resultAggregator) => new Promise((resolve, reject) => { /* do some work... */ })
  // ...
}).then(resultAggregator => {
  console.log('result from first Promise:', resultAggregator.phones.value)
  console.log('result from second Promise:', resultAggregator.laptops.value)
  // ...
}).catch(errResult => {
  console.error(`Error encountered on job (${ errResult.key}):`)
  console.error(errResult.reason)
  console.log('Managed to get these results before this error:')
  console.log(errResult.resultAggregator)
})

使用以前结果的例子:

import { runSequentialPromises } from 'quasar'

runSequentialPromises({
  phones: () => new Promise((resolve, reject) => { /* do some work... */ }),
  vendors: (resultAggregator) => {
    new Promise((resolve, reject) => {
      // You can do something with resultAggregator.phones.value here...
      // Since are using the default abortOnFail option, the result is guaranteed to exist,
      // so you don't have to guard resultAggregator.phones against "null"
    })
  }
  // ...
})

使用Axios的例子:

import { runSequentialPromises } from 'quasar'
import axios from 'axios'

const keyList = [ 'users', 'phones', 'laptops' ]

runSequentialPromises([
  () => axios.get('https://some-url.com/users'),
  () => axios.get('https://some-other-url.com/items/phones'),
  () => axios.get('https://some-other-url.com/items/laptops')
]).then(resultAggregator => {
  // resultAggregator is ordered in the same way as the promises above
  resultAggregator.forEach(result => {
    console.log(keyList[ result.key ], result.value) // example: users {...}
  })
}).catch(errResult => {
  console.error(`Error encountered while fetching ${ keyList[ errResult.key ] }:`)
  console.error(errResult.reason)
  console.log('Managed to get these results before this error:')
  console.log(errResult.resultAggregator)
})

// **equivalent** example with sequentialPromises as Object:

runSequentialPromises({
  users: () => axios.get('https://some-url.com/users'),
  phones: () => axios.get('https://some-other-url.com/items/phones'),
  laptops: () => axios.get('https://some-other-url.com/items/laptops')
}).then(resultAggregator => {
  console.log('users:', resultAggregator.users.value)
  console.log('phones:', resultAggregator.phones.value)
  console.log('laptops:', resultAggregator.laptops.value)
}).catch(errResult => {
  console.error(`Error encountered while fetching ${ errResult.key }:`)
  console.error(errResult.reason)
  console.log('Managed to get these results before this error:')
  console.log(errResult.resultAggregator)
})

例子中的abortOnFail设置为false

import { runSequentialPromises } from 'quasar'
import axios from 'axios'

// notice no "catch()"; runSequentialPromises() will always resolve
runSequentialPromises(
  {
    users: () => axios.get('https://some-url.com/users'),
    phones: () => axios.get('https://some-other-url.com/items/phones'),
    laptops: () => axios.get('https://some-other-url.com/items/laptops')
  },
  { abortOnFail: false }
).then(resultAggregator => {
  Object.values(resultAggregator).forEach(result => {
    if (result.status === 'rejected') {
      console.log(`Failed to fetch ${ result.key }:`, result.reason)
    }
    else {
      console.log(`Succeeded to fetch ${ result.key }:`, result.value)
    }
  })
})

当配置线程数(opts > threadsNumber)和使用http请求时,要注意托管浏览器支持的最大线程数(通常是5)。任何超过这个数量的线程都不会带来任何实际好处。

import { runSequentialPromises } from 'quasar'

runSequentialPromises([ /* ... */ ], { threadsNumber: 3 })
  .then(resultAggregator => {
    resultAggregator.forEach(result => {
      console.log(result.value)
    })
  })
  .catch(errResult => {
    console.error(`Error encountered:`)
    console.error(errResult.reason)
    console.log('Managed to get these results before this error:')
    console.log(errResult.resultAggregator)
  })

去抖(Debounce)函数

如果您的应用程序使用JavaScript来完成繁重的任务,那么去抖函数对于确保给定任务不会频繁触发以至于阻碍浏览器性能至关重要。去抖函数会限制函数的触发速率。

Debouncing强制一个函数不会被再次调用,直到经过一段时间而没有被调用。 正如“只有经过100毫秒而未被调用才执行此功能”。

一个简单的例子:在窗口上有一个调整大小的监听器,它执行一些元素尺寸计算并(可能)重新定位一些元素。 这本身并不是一项繁重的任务,但是经过多次调整后反复触发,真的会减慢你的App速度。 那么为什么不限制函数可以触发的速率呢?

// 返回一个函数,只要它继续被调用,就不会被触发。
// 该函数在停止被调用N毫秒后将被调用。 
// 如果传递`immediate`,则立即触发该函数
// 而不是拖延。
import { debounce } from 'quasar'

(Debounced Function) debounce(Function fn, Number milliseconds_to_wait, Boolean immediate)

// Example:
window.addEventListener(
  'resize',
  debounce(function() {
    //....要做的事情...
  }, 300 /*等待的毫秒*/)
)

或者作为.vue文件中的方法调用:

methods: {
  myMethod () { .... }
},

created () {
  this.myMethod = debounce(this.myMethod, 500)
}

WARNING

使用像myMethod: debounce(function () { // Code }, 500)这样的方法声明来将你的函数加上去抖效果(debouncing)将意味着debounce方法将在该组件的所有渲染实例之间共享,因此也可以共享去抖效果(debouncing)。 此外,this.myMethod.cancel()将不起作用,因为Vue将每个方法都由另一个函数封装以确保正确的this属性绑定。 应遵循上面的代码段来避免这种情况。

还有一个frameDebounce可用,它会延迟调用你的函数,直到下一个浏览器框架计划运行(阅读requestAnimationFrame)。

import { frameDebounce } from 'quasar'

(Debounced Function) frameDebounce(Function fn)

// 例子:
window.addEventListener(
  'resize',
  frameDebounce(function() {
    .... things to do ...
  })
)

节流(Throttle)功能

节流限制一定时间内一个函数可调用的最大次数。 如“每X毫秒最多执行一次该功能”。

import { throttle } from 'quasar'

(Throttled Function) throttle(Function fn, Number limit_in_milliseconds)

// 例子:
window.addEventListener(
  'resize',
  throttle(function() {
    .... things to do ...
  }, 300 /* 每0.3s最多执行一次 */)
)

或者作为.vue文件中的方法调用:

methods: {
  myMethod () { .... }
},

created () {
  this.myMethod = throttle(this.myMethod, 500)
}

WARNING

使用像myMethod: throttle(function () { // Code }, 500)这样的方法声明来将你的函数加上节流效果(throttling)将意味着throttle方法将在该组件的所有渲染实例之间共享,因此也可以共享节流效果(throttling)。 应遵循上面的代码段来避免这种情况。

(深)复制对象

和“jQuery.extend()`基本相同的方法。 采用相同的参数:

import { extend } from 'quasar'

let newObject = extend([Boolean deepCopy], targetObj, obj, ...)

注意对象内的方法。

生成UID

生成唯一标识符:

import { uid } from 'quasar'

let uid = uid()
// 例如: 501e7ae1-7e6f-b923-3e84-4e946bff31a8

处理DOM事件处理程序中的“事件”

它是跨浏览器的。

import { event } from 'quasar'

node.addEventListener('click', evt => {
  // 左点击?
  (Boolean) event.leftClick(evt)

  // 中间点击?
  (Boolean) event.middleClick(evt)

  // 右键点击?
  (Boolean) event.rightClick(evt)

  // 键入数字格式
  (Number) event.getEventKey(evt)

  // 鼠标滚轮滚动距离(以像素为单位)
  (Object {x, y}) event.getMouseWheelDistance(evt)

  // 在视区上的位置
   //适用于鼠标和触摸事件!
  (Object {top, left}) event.position(evt)

  // 获取目标DOM元素, 当鼠标或触摸
  // 事件已经发生时
  (DOM Element) event.targetElement(evt)

  // 调用stopPropagation和preventDefault
  event.stopAndPrevent(evt)
})