提交 115da7c5 编写于 作者: guangjun.yang's avatar guangjun.yang

创建项目

上级
{
"env": {
"test": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
}
}
Android >= 4.0
iOS >= 7
\ No newline at end of file
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# IDE / Editor
.idea
.editorconfig
# Service worker
sw.*
# Mac OSX
.DS_Store
\ No newline at end of file
# nuxt-ssr
# 记得部署的时候更改端口号:免得与现有项目冲突
> nuxt ssr layout
## Build Setup
``` bash
# install dependencies
$ npm run install
# serve with hot reload at localhost:3000
$ npm run dev
# build for production and launch server
# 有环境变量 非本地打包请自行带上ENV => dev, test, uat, prod
$ ENV=上一行的变量 npm run build // eg: ENV=dev npm run build
$ npm run start // 对于 start 命令,可以根据需求自行 更改PORT (有部署冲突的时候会改)
# generate static project // 暂时用不到
$ npm run generate
```
\ No newline at end of file
# ASSETS
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your un-compiled assets such as LESS, SASS, or JavaScript.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked).
# COMPONENTS
**This directory is not required, you can delete it if you don't want to use it.**
The components directory contains your Vue.js Components.
_Nuxt.js doesn't supercharge these components._
<template>
<div class="about-container">
about nuxtjs ssr
</div>
</template>
<script>
// asyncData fetch 在组件中无效
export default {
data() {
return {
name: 'about'
}
}
}
</script>
<style lang="less">
.about-container {
font-size: 18px;
}
</style>
\ No newline at end of file
module.exports = {
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: ['js', 'vue', 'json'],
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
'collectCoverage': true,
'collectCoverageFrom': [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue'
]
}
# LAYOUTS
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your Application Layouts.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts).
<template>
<div>
<nuxt />
</div>
</template>
<script>
export default {
mounted() {
this.$rocNative.appInit();
},
}
</script>
# MIDDLEWARE
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your application middleware.
Middleware let you define custom functions that can be run before rendering either a page or a group of pages.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware).
module.exports = {
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: '云鹊医-赋能基层医生',
meta: [
{ charset: 'utf-8' },
// { name: 'viewport', content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui' },
{ name: 'screen-orientation', content: 'portrait' },
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
{ name: 'format-detection', content: 'telephone=no' },
{ name: 'full-screen', content: 'yes' },
{ name: 'x5-fullscreen', content: 'true' },
{ name: 'referrer', content: 'never' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
// { rel: 'stylesheet', href: '/css/common.css' }
],
style: [
{ cssText: `
@charset "utf-8";html{color:#000;background:#fff;overflow-y:scroll;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}html *{outline:0;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}html,body{font-family:PingFangSC-Regular,-apple-system-font,Source Han Sans,Helvetica Neue,sans-serif}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}abbr,acronym{border:0;font-variant:normal}del{text-decoration:line-through}address,caption,cite,code,dfn,em,th,var{font-style:normal;font-weight:500}ol,ul{list-style:none}caption,th{text-align:left}q:before,q:after{content:''}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}a:hover{text-decoration:underline}ins,a{text-decoration:none}
`, type: 'text/css' }
],
__dangerouslyDisableSanitizers: ['script'],
script: [
{ innerHTML: `
!function(a,b){function c(){var b=f.getBoundingClientRect().width;b/i>540&&(b=540*i);var c=b/10;f.style.fontSize=c+"px",k.rem=a.rem=c}var d,e=a.document,f=e.documentElement,g=e.querySelector('meta[name="viewport"]'),h=e.querySelector('meta[name="flexible"]'),i=0,j=0,k=b.flexible||(b.flexible={});if(g){console.warn("将根据已有的meta标签来设置缩放比例");var l=g.getAttribute("content").match(/initial\-scale=([\d\.]+)/);l&&(j=parseFloat(l[1]),i=parseInt(1/j))}else if(h){var m=h.getAttribute("content");if(m){var n=m.match(/initial\-dpr=([\d\.]+)/),o=m.match(/maximum\-dpr=([\d\.]+)/);n&&(i=parseFloat(n[1]),j=parseFloat((1/i).toFixed(2))),o&&(i=parseFloat(o[1]),j=parseFloat((1/i).toFixed(2)))}}if(!i&&!j){var p=(a.navigator.appVersion.match(/android/gi),a.navigator.appVersion.match(/iphone/gi)),q=a.devicePixelRatio;i=p?q>=3&&(!i||i>=3)?3:q>=2&&(!i||i>=2)?2:1:1,j=1/i}if(f.setAttribute("data-dpr",i),!g)if(g=e.createElement("meta"),g.setAttribute("name","viewport"),g.setAttribute("content","initial-scale="+j+", maximum-scale="+j+", minimum-scale="+j+", user-scalable=no"),f.firstElementChild)f.firstElementChild.appendChild(g);else{var r=e.createElement("div");r.appendChild(g),e.write(r.innerHTML)}a.addEventListener("resize",function(){clearTimeout(d),d=setTimeout(c,300)},!1),a.addEventListener("pageshow",function(a){a.persisted&&(clearTimeout(d),d=setTimeout(c,300))},!1),"complete"===e.readyState?e.body.style.fontSize=12*i+"px":e.addEventListener("DOMContentLoaded",function(){e.body.style.fontSize=12*i+"px"},!1),c(),k.dpr=a.dpr=i,k.refreshRem=c,k.rem2px=function(a){var b=parseFloat(a)*this.rem;return"string"==typeof a&&a.match(/rem$/)&&(b+="px"),b},k.px2rem=function(a){var b=parseFloat(a)/this.rem;return"string"==typeof a&&a.match(/px$/)&&(b+="rem"),b}}(window,window.lib||(window.lib={}));
`, type: 'text/javascript', charset: 'utf-8'}
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
'vant/lib/index.css'
],
/*
** Plugins to load before mounting the App
*/
plugins: [
{
src: '~/plugins/vue-inject',
ssr: false
}
],
/*
** Nuxt.js modules
*/
modules: [],
/*
** Build configuration
*/
router: {
// base: '/nuxt_ssr/' //上下文根据自己的需求自行打开修改
},
build: {
postcss: {
plugins: {
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*']
}
}
},
extractCSS: true,
filenames: {
app: ({ isDev }) => isDev ? '[name].js' : '[name].[chunkhash:7].js',
chunk: ({ isDev }) => isDev ? '[name].js' : '[name].[chunkhash:7].js',
css: ({ isDev }) => isDev ? '[name].css' : '[name].[contenthash:7].css',
img: ({ isDev }) => isDev ? '[path][name].[ext]' : 'img/[name].[hash:7].[ext]',
font: ({ isDev }) => isDev ? '[path][name].[ext]' : 'fonts/[name].[hash:7].[ext]',
video: ({ isDev }) => isDev ? '[path][name].[ext]' : 'videos/[name].[hash:7].[ext]'
},
/*
** You can extend webpack config here
*/
extend(config, ctx) {
config.devtool = ['dev', 'test'].indexOf(process.env.NUXT_ENV_APP) !== -1 ? 'source-map' : false;
}
}
}
\ No newline at end of file
此差异已折叠。
{
"name": "nuxt_ssr",
"version": "1.0.0",
"description": "nuxt ssr layout",
"author": "souse",
"private": true,
"scripts": {
"test": "jest",
"dev": "cross-env NODE_ENV=development NUXT_ENV_APP=dev PORT=3000 nodemon server/index.js --watch server",
"build": "NUXT_ENV_APP=${ENV} nuxt build",
"start": "cross-env NUXT_ENV_APP=${ENV} HOST=0.0.0.0 PORT=3010 NODE_ENV=production node server/index.js",
"generate": "nuxt generate"
},
"dependencies": {
"cookie-universal": "^2.0.16",
"cross-env": "^5.2.0",
"koa": "^2.6.2",
"nuxt": "^2.0.0",
"vant": "^2.0.9",
"web-buried-point": "^2.0.0"
},
"devDependencies": {
"@nuxtjs/axios": "^5.5.4",
"@vue/test-utils": "^1.0.0-beta.27",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^24.1.0",
"jest": "^24.1.0",
"less": "^3.9.0",
"less-loader": "^5.0.0",
"nodemon": "^1.18.9",
"postcss-pxtorem": "^4.0.1",
"qs": "^6.7.0",
"vue-jest": "^3.0.3"
}
}
# PAGES
This directory contains your Application Views and Routes.
The framework reads all the `*.vue` files inside this directory and creates the router of your application.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing).
<template>
<div class="container">
<h1>nuxt-ssr</h1>
<about />
</div>
</template>
<script>
import request from '@/service/api'
import { getHospital } from '@/service';
import About from '../components/about';
export default {
components: {
About
},
async asyncData({ $axios }) {
console.log('index page async data');
const { data } = await request({
baseURL: 'https://sc.yunqueyi.com',
url: '/contents/template/116/widgetList?token=55122B14EAD64B77B4D65E083C994979&setEntry=true'
});
return { hos: data.model.widgetList }
},
fetch() {
console.log('index page fetch');
return {
fetch: 'fetch'
}
},
created() {
// this.$store.dispatch('searchHospital', { name: '测试' });
},
mounted() {}
}
</script>
<style lang="less">
.container {
margin: 0 auto;
min-height: 100vh;
h1 {
font-size: 36px;
text-align: center;
}
.m1 {
width: 100%;
> div {
width: 100%;
}
img {
width: 100%;
}
}
}
</style>
# PLUGINS
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).
import Vue from 'vue';
import { BASE_URL } from '@/utils/enumerate';
import rocNative from '@/utils/jsbridge';
import WebBuriedPoint, { sendBuriedData } from 'web-buried-point';
const { name } = require('../package.json');
const cookies = require('cookie-universal')();
const { NUXT_ENV_APP } = process.env;
Vue.prototype.$cookies = cookies;
Vue.prototype.$rocNative = new rocNative();
Vue.prototype.$sendBuriedData = sendBuriedData;
if (name === 'nuxt_ssr') throw Error('需要给当前项目起一个有意义的名称,多英文单词用 _ 拼接,不能有空格。修改文件:package.json (name)');
Vue.use(WebBuriedPoint, {
class_name: name,
url: `${BASE_URL[NUXT_ENV_APP]}/file/log/trace1`
});
\ No newline at end of file
const Koa = require('koa')
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
const app = new Koa()
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = !(app.env === 'production')
async function start() {
// Instantiate nuxt.js
const nuxt = new Nuxt(config)
const {
host = process.env.HOST || '127.0.0.1',
port = process.env.PORT || 3000
} = nuxt.options.server
// Build in development
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
} else {
await nuxt.ready()
}
app.use((ctx) => {
ctx.status = 200
ctx.respond = false // Bypass Koa's built-in response handling
ctx.req.ctx = ctx // This might be useful later on, e.g. in nuxtServerInit or with nuxt-stash
nuxt.render(ctx.req, ctx.res)
})
app.listen(port, host)
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true
})
}
start()
import Axios from 'axios';
import { Toast } from 'vant';
import { API_CONFIG, REPONSE_CODE } from '@/utils/enumerate';
const { VUE_ENV } = process.env; // server or client
const cookies = require('cookie-universal')();
Axios.interceptors.request.use(
config => {
// 0. Do something before request is sent
// 1. can be add loading
// 2. make sure if need token
const method = config.method.toLocaleLowerCase();
if (method === 'post' || method === 'put' || method === 'delete') {}
if (config.withCredentials) {
config.headers.token = cookies.get('token');
}
return config;
},
error => {
// when set loading close it
if (
error.code === 'ECONNABORTED' &&
error.message.indexOf('timeout') !== -1
) {
VUE_ENV === 'client' && Toast({ message: '请求超时', duration: 1000 });
}
return Promise.reject(error);
}
)
export default function(options) {
if (typeof options !== 'object') {
throw new Error('make sure the params options is an Object...');
}
const cf = JSON.parse(JSON.stringify(API_CONFIG));
options = Object.assign(cf, options); // 合并 config
return new Promise((resolve, reject) => {
Axios(options)
.then(res => {
const { status, data } = res;
if (status !== 200) {
let cmsg = REPONSE_CODE[status];
let message = cmsg !== undefined ? cmsg : '系统异常。';
throw Error(message);
}
if (!data) throw Error('axios reponse data in not defined.');
if (data.code != '000000') {
// 如果要是有其他特殊需求在此处添加
console.log(`调用后台接口报错,CODE: ${data.code},MESSAGE: ${data.message}。`);
}
resolve(res.data);
})
.catch(error => {
console.log('axios catch error: ', error.message);
VUE_ENV === 'client' && Toast({ message: error.message, duration: 1000 });
// reject(error);
})
})
}
\ No newline at end of file
import qs from 'qs';
import request from './api';
export const getHospital = async (params) => {
let query = { pageNum: 1, pageSize: 1, ...params };
const str = qs.stringify(query);
return request({ url: `/api-ws/hospitals/?${str}` });
};
\ No newline at end of file
# STATIC
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your static files.
Each file inside this directory is mapped to `/`.
Thus you'd want to delete this README.md before deploying to production.
Example: `/static/robots.txt` is mapped as `/robots.txt`.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).
@charset "utf-8";
html {
color: #000;
background: #fff;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%
}
html * {
outline: 0;
-webkit-text-size-adjust: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}
html,body {
font-family: PingFangSC-Regular, -apple-system-font, Source Han Sans, Helvetica Neue, sans-serif;
}
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, hr, button, article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
margin: 0;
padding: 0;
}
/*
input, select, textarea {
font-size: 100%;
}
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
fieldset, img {
border: 0;
}
abbr, acronym {
border: 0;
font-variant: normal;
}
del {
text-decoration: line-through;
}
address, caption, cite, code, dfn, em, th, var {
font-style: normal;
font-weight: 500;
}
ol, ul {
list-style: none;
}
caption, th {
text-align: left;
}
/*
h1, h2, h3, h4, h5, h6 {
font-size: 100%;
font-weight: 500;
}
*/
q:before, q:after {
content: '';
}
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -.5em;
}
sub {
bottom: -.25em;
}
a:hover {
text-decoration: underline;
}
ins, a {
text-decoration: none;
}
;(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {});
if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
var content = flexibleEl.getAttribute('content');
if (content) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
dpr = parseFloat(initialDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === 'complete') {
doc.body.style.fontSize = 12 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
doc.body.style.fontSize = 12 * dpr + 'px';
}, false);
}
refreshRem();
flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
}
})(window, window['lib'] || (window['lib'] = {}));
\ No newline at end of file
# STORE
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your Vuex Store files.
Vuex Store option is implemented in the Nuxt.js framework.
Creating a file in this directory automatically activates the option in the framework.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).
import { getHospital } from '@/service';
export const state = () => ({
hospitals: []
});
export const mutations = {
add (state, { data }) {
console.log('mutations add hospital: ', data);
state.hospitals = data;
}
};
export const actions = {
async searchHospital({ commit }, { name }) {
getHospital({ name }).then(res => {
commit('add', res);
return res;
});
}
};
import { mount } from '@vue/test-utils'
import Logo from '@/components/Logo.vue'
describe('Logo', () => {
test('is a Vue instance', () => {
const wrapper = mount(Logo)
expect(wrapper.isVueInstance()).toBeTruthy()
})
})
const { NUXT_ENV_APP } = process.env;
export const BASE_URL = {
dev: 'https://dev-sc.yunqueyi.com',
test: 'https://test1-sc.yunqueyi.com',
prod: 'https://sc.yunqueyi.com'
};
export const API_CONFIG = {
baseURL: BASE_URL[NUXT_ENV_APP],
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json;charset=UTF-8'
},
timeout: 10000,
withCredentials: false,
responseType: 'json',
method: 'get'
}
export const REPONSE_CODE = {
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(登录过期、token错误)',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。'
};
export const getSearchByName = name => {
const match = RegExp(`[?&]${name}=([^&]*)`).exec(window.location.href);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
};
export const getItem = name => {
if (!name) return;
const v = sessionStorage.getItem(name);
let val = null;
try {
val = JSON.parse(v);
} catch (e) {
// JSON.parse 失败 后 直接赋v给val;
val = v;
}
return val;
};
export const setItem = (name, value) => {
if (!name) return;
if (typeof value !== 'string') {
value = JSON.stringify(value);
}
sessionStorage.setItem(name, value);
};
export const removeItem = name => {
if (!name) return;
sessionStorage.removeItem(name);
};
\ No newline at end of file
/*
* @Author: souse
* @Date: 2019-08-12 18:08:07
* @Last Modified by: souse
* @Last Modified time: 2019-08-13 19:17:00
* @Descript 和app交互的接口调用 单例模式
*/
const ARRAY_CLASS = '[object Array]';
const _toString = Object.prototype.toString;
/**
* set default options
*/
export const JsBridgeOptions = {
GLOBAL_NAME: 'rocNative',
NATIVE_IOS_NAME: 'rociOS',
NATIVE_ANDROID_NAME: '__rocAndroid',
initMethodsWithCallBack: ['getToken', 'getUserInfo', 'getLocalData'], // value is string
initMethodsWithoutCallBack: [
'gotoLogin',
'appInit',
'goBack',
'shareWechat',
'showNativeToast',
'dispatchEventByModuleCode',
'appBuryingPointEntrust',
'webLoadSuccess',
'sendBuriedPoint',
'openErrorDebug'
] // value is string
}
/**
* @description
* @author souse
* @date 2019-08-12
* @export
* @class PicaJsBridge
*/
export default class PicaJsBridge {
constructor(options = JsBridgeOptions) {
const initMethodsWithCallBack = options.initMethodsWithCallBack;
const initMethodsWithoutCallBack = options.initMethodsWithoutCallBack;
this._callbakFns = {};
this._callbackId = 0;
this._GLOBAL_NAME = options.GLOBAL_NAME;
this._NATIVE_IOS_NAME = options.NATIVE_IOS_NAME;
this._NATIVE_ANDROID_NAME = options.NATIVE_ANDROID_NAME;
this.isIOS = this._isIos();
this.isAndroid = this._isAndroid();
this.isWeb = this._isWeb();
if (_toString.call(initMethodsWithCallBack) === ARRAY_CLASS && initMethodsWithCallBack.length !== 0) {
this.registerMethods(initMethodsWithCallBack, true);
}
if (_toString.call(initMethodsWithoutCallBack) === ARRAY_CLASS && initMethodsWithoutCallBack.length !== 0) {
this.registerMethods(initMethodsWithoutCallBack, false);
}
this.mountToWindow();
}
// is ios flag
_isIos() {
return !!(window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers[this._NATIVE_IOS_NAME]);
}
// is android flag
_isAndroid() {
return !!window[this._NATIVE_ANDROID_NAME];
}
// is web flag
_isWeb() {
return !this.isIOS && !this.isAndroid;
}
// register method width callback in window
_registerMethod(method) {
const _this = this;
_this[method] = (param) => {
return new Promise((response, reject) => {
_this._callNative(method, param, function(result) {
response(result);
}) ? void 0 : reject(`${method} not handled.`);
});
}
}
// register method widthout callback in window
_registerMethodWithoutMethod(method) {
const _this = this;
_this[method] = (param) => {
return new Promise((response, reject) => {
_this._callNative(method, param, null) ? response('success') : reject(`${method} not handled.`);
});
}
}
// window call app method
_callNative(name, param, callbackFn) {
let callbackId = 0, pm;
if (typeof callbackFn === 'function') {
this._callbackId++;
callbackId = this._callbackId;
this._callbakFns[callbackId] = callbackFn;
}
pm = JSON.stringify({
name,
callbackId: callbackId ? callbackId.toString() : '',
param: param || {}
});
if (this.isAndroid) {
window[this._NATIVE_ANDROID_NAME].postMessage(pm);
return true;
}
if (this.isIOS) {
window.webkit.messageHandlers[this._NATIVE_IOS_NAME].postMessage(pm);
return true;
}
return false;
}
// app call window method
__nativeCall(name, callbackId, result) {
const wFun = window[callbackId];
const fun = callbackId && this._callbakFns[callbackId];
//add by zhangping
if (wFun && typeof wFun === 'function') {
wFun(result);
return;
}
delete this._callbakFns[callbackId];
if (fun && typeof fun === 'function') fun(result);
}
// batch register methods
registerMethods(methods = [], widthCallback) {
if (undefined === widthCallback)
throw Error('widthCallback flag not defined, registerMethods should take second param value(true/false) for is not has callback.');
methods.forEach(m => {
widthCallback === true ? this._registerMethod(m) : this._registerMethodWithoutMethod(m)
});
}
// async call app method do not need register
asyncCallNative(method, param) {
const _this = this;
return new Promise(resolve => {
_this._callNative(method, param, function(result) {
resolve(result);
});
});
}
// call app method direct without register and callback
callNative(method, param) {
return this._callNative(method, param, null);
}
// register jsbridge to window
mountToWindow() {
window[this._GLOBAL_NAME] = this;
}
}
\ No newline at end of file
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册