0
点赞
收藏
分享

微信扫一扫

vue使用jsonp请求

Vue-jsonp

Install

npm install vue-jsonp -S

用法

    1. 在main.js中添加,注册为Vue的全局插件
import { VueJsonp } from 'vue-jsonp'
Vue.use(VueJsonp)

现在你可以在Vue的组件中使用 this.$jsonp 发送 jsonp 请求了,因为Vue.use(VueJsonp)里把 $jsonp 赋给 vue 原型了:Vue.prototype.$jsonp = jsonp
例如请求百度地图接口:

     this.$jsonp('https://apis.map.qq.com/ws/place/v1/suggestion', {
region: "杭州",
keyword: query,
key: "CCWBZ-LZD6S-67COM-6GWDO-CHJ67-*****",
output: 'jsonp'
}).then(res => {
// ...
})
    1. 在组件中直接使用函数:
      import { jsonp } from 'vue-jsonp'

jsonp('https://apis.map.qq.com/ws/place/v1/suggestion', {
region: "杭州",
keyword: query,
key: "CCWBZ-LZD6S-67COM-6GWDO-CHJ67-*****",
output: 'jsonp'
}).then(res => {
// ...
})
  • 发送数据和设置查询参数 & 函数名
// The request url will be "/some-jsonp-url?name=LancerComet&age=100&callback=jsonp_{RANDOM_STR}".
jsonp('/some-jsonp-url', {
name: 'LancerComet',
age: 100
})
  • 自定义查询和函数名
// The request url will be "/some-jsonp-url?name=LancerComet&age=100&cb=jsonp_func".
jsonp('/some-jsonp-url', {
callbackQuery: 'cb',
callbackName: 'jsonp_func',
name: 'LancerComet',
age: 100
})

部分源码分析


vue-jsonp是使用rollupjs作为打包工具,采用typescript语法进行开发。入口文件./lib/index.ts 核心代码也就185行代码,挺精简了。

import Vue from 'vue'
import { PluginObject } from 'vue/types/plugin'
import { flatten, formatParams, randomStr } from './utils'

const DEFAULT_TIMEOUT: number = 5000

declare module 'vue/types/vue' {
// tslint:disable-next-line:interface-name
interface Vue {
$jsonp: typeof jsonp
}
}

/**
* Vue JSONP.
*/

// tslint:disable-next-line:variable-name
const VueJsonp: PluginObject<never> = {
install (V: typeof Vue) {
V.prototype.$jsonp = jsonp
}
}


// ....
export {
VueJsonp,
jsonp
}

在 TypeScript 中制作插件需要类型声明,项目中使用TypeScript 模块补充 (module augmentation)的特性,在declare module 'vue/types/vue' 中声明了 Vue 要补充的 $jsonp 类型,注册VueJsonp插件, 将$jsonp 赋给 vue 原型,将jsonp 函数挂载到Vue.prototype.$jsonp上。

const VueJsonp: PluginObject<never> = {
install (V: typeof Vue) {
V.prototype.$jsonp = jsonp
}
}

jsonp()

  • jsonp函数就是动态创建了script标签,利用<script>的src不受同源策略约束来跨域获取数据
  • 在window对象上根据callbackName创建全局回调函数来接收数据,将请求地址拼接上请求参数,并挂载到document上,等服务端响应并返回约定的数据,返回一个promise实例, resolve(json)
  • JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。
function jsonp<T = any> (
url: string,
param: IJsonpParam = {},
timeout?: number
): Promise<T> {
if (typeof url !== 'string') {
throw new Error('[Vue-jsonp] Type of param "url" is not string.')
}

if (typeof param !== 'object' || !param) {
throw new Error('[Vue-jsonp] Invalid params, should be an object.')
}

timeout = typeof timeout === 'number'
? timeout
: DEFAULT_TIMEOUT

return new Promise<T>((resolve, reject) => {
const callbackQuery = typeof param.callbackQuery === 'string'
? param.callbackQuery
: 'callback'
const callbackName = typeof param.callbackName === 'string'
? param.callbackName
: 'jsonp_' + randomStr()

param[callbackQuery] = callbackName

// Remove callbackQuery and callbackName.
delete param.callbackQuery
delete param.callbackName

// Convert params to querying str.
let queryStrs: (string[])[] = []
Object.keys(param).forEach(queryKey => {
queryStrs = queryStrs.concat(formatParams(queryKey, param[queryKey]))
})

const queryStr = flatten(queryStrs).join('&')

const onError = () => {
removeErrorListener()
clearTimeout(timeoutTimer)
reject({
status: 400,
statusText: 'Bad Request'
})
}

const removeErrorListener = () => {
paddingScript.removeEventListener('error', onError)
}

const removeScript = () => {
document.body.removeChild(paddingScript)
delete window[callbackName]
}

// Timeout timer.
let timeoutTimer = null

// Setup timeout.
if (timeout > -1) {
timeoutTimer = setTimeout(() => {
removeErrorListener()
removeScript()
reject({
statusText: 'Request Timeout',
status: 408
})
}, timeout)
}

// Create global function.
window[callbackName] = (json: T) => {
clearTimeout(timeoutTimer)
removeErrorListener()
removeScript()
resolve(json)
}

// Create script element.
const paddingScript = document.createElement('script')

// Add error listener.
paddingScript.addEventListener('error', onError)

// Append to head element.
paddingScript.src = url + (/\?/.test(url) ? '&' : '?') + queryStr
document.body.appendChild(paddingScript)
})
}

参考资料

vue-jsonp - npm
vue-jsonp - github

举报

相关推荐

0 条评论