diff --git a/packages/vue-cli-plugin-hbuilderx/build/webpack.nvue.conf.js b/packages/vue-cli-plugin-hbuilderx/build/webpack.nvue.conf.js index 4e032f5d511f249ee96d1d8417c8cb0d40dd43f6..246761eb2c44e157f84de07cac9d2d2dbf5fb374 100644 --- a/packages/vue-cli-plugin-hbuilderx/build/webpack.nvue.conf.js +++ b/packages/vue-cli-plugin-hbuilderx/build/webpack.nvue.conf.js @@ -100,7 +100,7 @@ const rules = [{ { test: /\.nvue(\?[^?]+)?$/, use: [{ - loader: 'vue-loader', + loader: path.resolve(__dirname, '../packages/vue-loader'), options: vueLoaderOptions }], exclude: excludeModuleReg @@ -108,7 +108,7 @@ const rules = [{ { test: /\.vue(\?[^?]+)?$/, use: [{ - loader: 'vue-loader', + loader: path.resolve(__dirname, '../packages/vue-loader'), options: vueLoaderOptions }], exclude: excludeModuleReg @@ -146,6 +146,15 @@ if (process.env.UNI_USING_NVUE_COMPILER) { }] }) } +rules.unshift({ + resourceQuery: function (query) { + return query.indexOf('vue&type=template') !== -1 && query.indexOf('mpType=page') === -1 + }, + use: [{ + loader: '@dcloudio/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/template.recycle' + }] +}) + if (process.env.UNI_USING_NATIVE) { plugins.push(new WebpackUniMPPlugin()) plugins.push(new CopyWebpackPlugin([{ @@ -185,7 +194,7 @@ module.exports = function () { 'vue': 'Vue' }, optimization: { - namedModules: false + namedModules: false }, output: { path: process.env.UNI_OUTPUT_DIR, @@ -198,6 +207,9 @@ module.exports = function () { '@': process.env.UNI_INPUT_DIR, 'uni-pages': path.resolve(process.env.UNI_INPUT_DIR, 'pages.json'), '@dcloudio/uni-stat': require.resolve('@dcloudio/uni-stat'), + 'uni-app-style': path.resolve(process.env.UNI_INPUT_DIR, getNVueMainEntry()) + '?' + JSON.stringify({ + type: 'appStyle' + }), 'uni-stat-config': path.resolve(process.env.UNI_INPUT_DIR, 'pages.json') + '?' + JSON.stringify({ @@ -205,7 +217,7 @@ module.exports = function () { }) }, modules: [ - 'node_modules', + 'node_modules', path.resolve(process.env.UNI_CLI_CONTEXT, 'node_modules'), path.resolve(process.env.UNI_INPUT_DIR, 'node_modules') ] diff --git a/packages/vue-cli-plugin-hbuilderx/module-alias.js b/packages/vue-cli-plugin-hbuilderx/module-alias.js index d9c0a2333a4d352348f65885764cd0f1f97e5a9a..4c32e657bf06756e54db5c67e80c248a0943ea1a 100644 --- a/packages/vue-cli-plugin-hbuilderx/module-alias.js +++ b/packages/vue-cli-plugin-hbuilderx/module-alias.js @@ -9,9 +9,16 @@ const { // override moduleAlias.addAlias('weex-styler', path.resolve(__dirname, 'packages/weex-styler')) moduleAlias.addAlias('weex-template-compiler', path.resolve(__dirname, 'packages/weex-template-compiler')) +moduleAlias.addAlias('./compileTemplate', path.resolve(__dirname, + 'packages/webpack-uni-nvue-loader/lib/compileTemplate')) moduleAlias.addAlias('./codegen/styleInjection', path.resolve(__dirname, 'packages/webpack-uni-nvue-loader/lib/styleInjection')) - +moduleAlias.addAlias('./templateLoader', (fromPath, request, alias) => { + if (fromPath.indexOf('vue-loader') !== -1) { + return path.resolve(__dirname, 'packages/webpack-uni-nvue-loader/lib/templateLoader') + } + return request +}) if (isInHBuilderX) { moduleAlias.addAlias('typescript', path.resolve(process.env.UNI_HBUILDERX_PLUGINS, 'compile-typescript/node_modules/typescript')) diff --git a/packages/vue-cli-plugin-hbuilderx/packages/vue-loader/index.js b/packages/vue-cli-plugin-hbuilderx/packages/vue-loader/index.js new file mode 100644 index 0000000000000000000000000000000000000000..532d69ab932a5ad791c3b5461d61214465bf6834 --- /dev/null +++ b/packages/vue-cli-plugin-hbuilderx/packages/vue-loader/index.js @@ -0,0 +1,211 @@ +const path = require('path') +const hash = require('hash-sum') +const qs = require('querystring') +const plugin = require('vue-loader/lib/plugin') +const selectBlock = require('vue-loader/lib/select') +const loaderUtils = require('loader-utils') +const { attrsToQuery } = require('vue-loader/lib/codegen/utils') +const { parse } = require('@vue/component-compiler-utils') +const genStylesCode = require('../webpack-uni-nvue-loader/lib/styleInjection') +const { genHotReloadCode } = require('vue-loader/lib/codegen/hotReload') +const genCustomBlocksCode = require('vue-loader/lib/codegen/customBlocks') +const componentNormalizerPath = require.resolve('vue-loader/lib/runtime/componentNormalizer') +const { NS } = require('vue-loader/lib/plugin') + +let errorEmitted = false + +function loadTemplateCompiler (loaderContext) { + try { + return require('vue-template-compiler') + } catch (e) { + if (/version mismatch/.test(e.toString())) { + loaderContext.emitError(e) + } else { + loaderContext.emitError(new Error( + `[vue-loader] vue-template-compiler must be installed as a peer dependency, ` + + `or a compatible compiler implementation must be passed via options.` + )) + } + } +} + +function hasRecyclable (template) { + return !!(template && template.attrs && template.attrs.recyclable) +} + +module.exports = function (source) { + const loaderContext = this + + if (!errorEmitted && !loaderContext['thread-loader'] && !loaderContext[NS]) { + loaderContext.emitError(new Error( + `vue-loader was used without the corresponding plugin. ` + + `Make sure to include VueLoaderPlugin in your webpack config.` + )) + errorEmitted = true + } + + const stringifyRequest = r => loaderUtils.stringifyRequest(loaderContext, r) + + const { + target, + request, + minimize, + sourceMap, + rootContext, + resourcePath, + resourceQuery + } = loaderContext + + const rawQuery = resourceQuery.slice(1) + const inheritQuery = `&${rawQuery}` + const incomingQuery = qs.parse(rawQuery) + const options = loaderUtils.getOptions(loaderContext) || {} + + const isServer = target === 'node' + const isShadow = !!options.shadowMode + const isProduction = options.productionMode || minimize || process.env.NODE_ENV === 'production' + const filename = path.basename(resourcePath) + const context = rootContext || process.cwd() + const sourceRoot = path.dirname(path.relative(context, resourcePath)) + + const descriptor = parse({ + source, + compiler: options.compiler || loadTemplateCompiler(loaderContext), + filename, + sourceRoot, + needMap: sourceMap + }) + + // if the query has a type field, this is a language block request + // e.g. foo.vue?type=template&id=xxxxx + // and we will return early + if (incomingQuery.type) { + return selectBlock( + descriptor, + loaderContext, + incomingQuery, + !!options.appendExtension + ) + } + + // module id for scoped CSS & hot-reload + const rawShortFilePath = path + .relative(context, resourcePath) + .replace(/^(\.\.[\/\\])+/, '') + + const shortFilePath = rawShortFilePath.replace(/\\/g, '/') + resourceQuery + + const id = hash( + isProduction + ? (shortFilePath + '\n' + source) + : shortFilePath + ) + + // feature information + const hasScoped = descriptor.styles.some(s => s.scoped) + const hasFunctional = descriptor.template && descriptor.template.attrs.functional + const needsHotReload = ( + !isServer && + !isProduction && + (descriptor.script || descriptor.template) && + options.hotReload !== false + ) + + // template + let templateImport = `var render, staticRenderFns` + let templateRequest + const recyclable = hasRecyclable(descriptor.template) // fixed by xxxxxx + if (descriptor.template) { + const src = descriptor.template.src || resourcePath + const idQuery = `&id=${id}` + const scopedQuery = hasScoped ? `&scoped=true` : `` + const attrsQuery = attrsToQuery(descriptor.template.attrs) + const query = `?vue&type=template${idQuery}${scopedQuery}${attrsQuery}${inheritQuery}` + const request = templateRequest = stringifyRequest(src + query) + if(recyclable){ // fixed by xxxxxx + templateImport = `import { render, staticRenderFns, recyclableRender } from ${request}` + } else { + templateImport = `import { render, staticRenderFns } from ${request}` + } + } + + // script + let scriptImport = `var script = {}` + if (descriptor.script) { + const src = descriptor.script.src || resourcePath + const attrsQuery = attrsToQuery(descriptor.script.attrs, 'js') + const query = `?vue&type=script${attrsQuery}${inheritQuery}` + const request = stringifyRequest(src + query) + scriptImport = ( + `import script from ${request}\n` + + `export * from ${request}` // support named exports + ) + } + + // styles + let stylesCode = `` + if (descriptor.styles.length) { + stylesCode = genStylesCode( + loaderContext, + descriptor.styles, + id, + resourcePath, + stringifyRequest, + needsHotReload, + isServer || isShadow // needs explicit injection? + ) + } + + let code = ` +${templateImport} +${scriptImport} +${stylesCode} + +/* normalize component */ +import normalizer from ${stringifyRequest(`!${componentNormalizerPath}`)} +var component = normalizer( + script, + render, + staticRenderFns, + ${hasFunctional ? `true` : `false`}, + ${`null`}, + ${hasScoped ? JSON.stringify(id) : `null`}, + ${isServer ? JSON.stringify(hash(request)) : `null`} + ${isShadow ? `,true` : ``} +) + `.trim() + `\n` + + if (descriptor.customBlocks && descriptor.customBlocks.length) { + code += genCustomBlocksCode( + descriptor.customBlocks, + resourcePath, + resourceQuery, + stringifyRequest + ) + } + + if (needsHotReload) { + code += `\n` + genHotReloadCode(id, hasFunctional, templateRequest) + } + if(/injectStyles/.test(stylesCode)){// fixed by xxxxxx + code +=`\ninjectStyles.call(component)` + } + // Expose filename. This is used by the devtools and Vue runtime warnings. + if (!isProduction) { + // Expose the file's full path in development, so that it can be opened + // from the devtools. + code += `\ncomponent.options.__file = ${JSON.stringify(rawShortFilePath.replace(/\\/g, '/'))}` + } else if (options.exposeFilename) { + // Libraies can opt-in to expose their components' filenames in production builds. + // For security reasons, only expose the file's basename in production. + code += `\ncomponent.options.__file = ${JSON.stringify(filename)}` + } + if(recyclable){ + code += `\nrecyclableRender && (component.options["@render"] = recyclableRender)` // fixed by xxxxxx + } + code += `\nexport default component.exports` + // console.log(code) + return code +} + +module.exports.VueLoaderPlugin = plugin diff --git a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/compileTemplate.js b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/compileTemplate.js new file mode 100644 index 0000000000000000000000000000000000000000..5e056dc5451e62df8a76d5c77df9e71f0c69cbc6 --- /dev/null +++ b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/compileTemplate.js @@ -0,0 +1,114 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const assetUrl_1 = __importDefault(require("@vue/component-compiler-utils/dist/templateCompilerModules/assetUrl")); +const srcset_1 = __importDefault(require("@vue/component-compiler-utils/dist/templateCompilerModules/srcset")); +const consolidate = require('consolidate'); +const transpile = require('vue-template-es2015-compiler'); +function compileTemplate(options) { + const { preprocessLang } = options; + const preprocessor = preprocessLang && consolidate[preprocessLang]; + if (preprocessor) { + return actuallyCompile(Object.assign({}, options, { + source: preprocess(options, preprocessor) + })); + } + else if (preprocessLang) { + return { + code: `var render = function () {}\n` + `var staticRenderFns = []\n`, + source: options.source, + tips: [ + `Component ${options.filename} uses lang ${preprocessLang} for template. Please install the language preprocessor.` + ], + errors: [ + `Component ${options.filename} uses lang ${preprocessLang} for template, however it is not installed.` + ] + }; + } + else { + return actuallyCompile(options); + } +} +exports.compileTemplate = compileTemplate; +function preprocess(options, preprocessor) { + const { source, filename, preprocessOptions } = options; + const finalPreprocessOptions = Object.assign({ + filename + }, preprocessOptions); + // Consolidate exposes a callback based API, but the callback is in fact + // called synchronously for most templating engines. In our case, we have to + // expose a synchronous API so that it is usable in Jest transforms (which + // have to be sync because they are applied via Node.js require hooks) + let res, err; + preprocessor.render(source, finalPreprocessOptions, (_err, _res) => { + if (_err) + err = _err; + res = _res; + }); + if (err) + throw err; + return res; +} +function actuallyCompile(options) { + const { source, compiler, compilerOptions = {}, transpileOptions = {}, transformAssetUrls, isProduction = process.env.NODE_ENV === 'production', isFunctional = false, optimizeSSR = false, prettify = true } = options; + const compile = optimizeSSR && compiler.ssrCompile ? compiler.ssrCompile : compiler.compile; + let finalCompilerOptions = compilerOptions; + if (transformAssetUrls) { + const builtInModules = [ + transformAssetUrls === true + ? assetUrl_1.default() + : assetUrl_1.default(transformAssetUrls), + srcset_1.default() + ]; + finalCompilerOptions = Object.assign({}, compilerOptions, { + modules: [...builtInModules, ...(compilerOptions.modules || [])] + }); + } + const { render, staticRenderFns, tips, errors, '@render': recyclableRender } = compile(source, finalCompilerOptions); + if (errors && errors.length) { + return { + code: `var render = function () {}\n` + `var staticRenderFns = []\n`, + source, + tips, + errors + }; + } + else { + const finalTranspileOptions = Object.assign({}, transpileOptions, { + transforms: Object.assign({}, transpileOptions.transforms, { + stripWithFunctional: isFunctional + }) + }); + const toFunction = (code) => { + return `function (${isFunctional ? `_h,_vm` : ``}) {${code}}`; + }; + // transpile code with vue-template-es2015-compiler, which is a forked + // version of Buble that applies ES2015 transforms + stripping `with` usage + let code = transpile(`var __render__ = ${toFunction(render)}\n` + + (recyclableRender ? (`var __recyclableRender__ = ${toFunction(recyclableRender)}\n`) : '') + + `var __staticRenderFns__ = [${staticRenderFns.map(toFunction)}]`, finalTranspileOptions) + `\n`; + // #23 we use __render__ to avoid `render` not being prefixed by the + // transpiler when stripping with, but revert it back to `render` to + // maintain backwards compat + code = code.replace(/\s__(render|recyclableRender|staticRenderFns)__\s/g, ' $1 '); + if (!isProduction) { + // mark with stripped (this enables Vue to use correct runtime proxy + // detection) + code += `render._withStripped = true`; + if (prettify) { + code = require('prettier').format(code, { + semi: false, + parser: 'babel' + }); + } + } + return { + code, + source, + tips, + errors + }; + } +} diff --git a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/main.js b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/main.js index 907954416d9e5d44cde366006710e8b7e23e2301..ddf3183555ef7b69695eadc535c660abb7f03300 100644 --- a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/main.js +++ b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/main.js @@ -28,7 +28,7 @@ function getAppStyleCode(stringifyRequest) { if (!process.env.UNI_USING_NVUE_COMPILER) { return '' } - let code = 'App.appStyle = {}\n' + let code = 'Vue.prototype.__$appStyle__ = {}\n' let styles = [] try { if (fs.existsSync(appVuePath)) { @@ -37,7 +37,7 @@ function getAppStyleCode(stringifyRequest) { } catch (e) {} styles.forEach((style, index) => { code = code + - `Vue.prototype.__merge_style(require(${genStyleRequest(style,index,stringifyRequest)}).default,App.appStyle)\n` + `Vue.prototype.__merge_style && Vue.prototype.__merge_style(require(${genStyleRequest(style,index,stringifyRequest)}).default,Vue.prototype.__$appStyle__)\n` }) return code } @@ -51,22 +51,25 @@ module.exports = function(content) { if (this.resourceQuery) { const params = loaderUtils.parseQuery(this.resourceQuery) - if (params && params.page) { - - const stringifyRequest = r => loaderUtils.stringifyRequest(loaderContext, r) - - params.page = decodeURIComponent(params.page) - // import Vue from 'vue'是为了触发 vendor 合并 - return ` -${statCode} -import App from './${normalizePath(params.page)}.nvue?mpType=page' -App.mpType = 'page' -App.route = '${params.page}' -App.el = '#root' -${getAppStyleCode(stringifyRequest)} -new Vue(App) -` + if (params) { + if (params.page) { + params.page = decodeURIComponent(params.page) + // import Vue from 'vue'是为了触发 vendor 合并 + return ` + ${statCode} + import 'uni-app-style' + import App from './${normalizePath(params.page)}.nvue?mpType=page' + App.mpType = 'page' + App.route = '${params.page}' + App.el = '#root' + new Vue(App) + ` + } else if (params.type === 'appStyle') { + const stringifyRequest = r => loaderUtils.stringifyRequest(loaderContext, r) + return `${getAppStyleCode(stringifyRequest)}` + } } + } return statCode + content } diff --git a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/styleInjection.js b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/styleInjection.js index dd84223b02f677a24877f04ad218e0d76af7c3db..e684809bc2f40dbf41b4ba86ba221fe0448eb116 100644 --- a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/styleInjection.js +++ b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/styleInjection.js @@ -86,21 +86,21 @@ module.exports = function genStyleInjectionCode ( } }) } else { - styleInjectionCode = `if(!this.$options.style){ - this.$options.style = {} + styleInjectionCode = `if(!this.options.style){ + this.options.style = {} } -if(this.__merge_style && this.$root && this.$root.$options.appStyle){ - this.__merge_style(this.$root.$options.appStyle) +if(Vue.prototype.__merge_style && Vue.prototype.__$appStyle__){ + Vue.prototype.__merge_style(Vue.prototype.__$appStyle__, this.options.style) } ` styles.forEach((style, i) => { if (isNotEmptyStyle(style)) { const request = genStyleRequest(style, i) styleInjectionCode += ( - `if(this.__merge_style){ - this.__merge_style(require(${request}).default) + `if(Vue.prototype.__merge_style){ + Vue.prototype.__merge_style(require(${request}).default, this.options.style) }else{ - Object.assign(this.$options.style,require(${request}).default) + Object.assign(this.options.style,require(${request}).default) }\n`//fixed by xxxxxx 简单处理,与 weex-vue-loader 保持一致 //`var style${i} = require(${request})\n` + //`if (style${i}.__inject__) style${i}.__inject__(context)\n` @@ -119,8 +119,7 @@ ${styleImportsCode} ${hasCSSModules && needsHotReload ? `var cssModules = {}` : ``} ${needsHotReload ? `var disposed = false` : ``} -function injectStyles (context) { - ${needsHotReload ? `if (disposed) return` : ``} +function injectStyles () { ${styleInjectionCode} } diff --git a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/template.recycle.js b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/template.recycle.js new file mode 100644 index 0000000000000000000000000000000000000000..f812d34fc23a6f9c45a5ce2f725dab8943d8a20a --- /dev/null +++ b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/template.recycle.js @@ -0,0 +1,18 @@ +const loaderUtils = require('loader-utils') +module.exports = function(content) { + this.cacheable && this.cacheable() + + const vueLoaderOptions = this.loaders[0] + if (vueLoaderOptions.ident === 'vue-loader-options') { + const params = loaderUtils.parseQuery(this.resourceQuery) + if (params.recyclable) { + Object.assign(vueLoaderOptions.options.compilerOptions, { + recyclable: true + }) + } + } else { + throw new Error('vue-loader-options parse error') + } + + return content +} diff --git a/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/templateLoader.js b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/templateLoader.js new file mode 100644 index 0000000000000000000000000000000000000000..f820630a524bf0f0871737b0422b4ddf926edf9c --- /dev/null +++ b/packages/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/templateLoader.js @@ -0,0 +1,92 @@ +const qs = require('querystring') +const loaderUtils = require('loader-utils') +const { compileTemplate } = require('@vue/component-compiler-utils') + +// Loader that compiles raw template into JavaScript functions. +// This is injected by the global pitcher (../pitch) for template +// selection requests initiated from vue files. +module.exports = function (source) { + const loaderContext = this + const query = qs.parse(this.resourceQuery.slice(1)) + + // although this is not the main vue-loader, we can get access to the same + // vue-loader options because we've set an ident in the plugin and used that + // ident to create the request for this loader in the pitcher. + const options = loaderUtils.getOptions(loaderContext) || {} + const { id } = query + const isServer = loaderContext.target === 'node' + const isProduction = options.productionMode || loaderContext.minimize || process.env.NODE_ENV === 'production' + const isFunctional = query.functional + + // allow using custom compiler via options + const compiler = options.compiler || require('vue-template-compiler') + + const compilerOptions = Object.assign({ + outputSourceRange: true + }, options.compilerOptions, { + scopeId: query.scoped ? `data-v-${id}` : null, + comments: query.comments + }) + + // for vue-component-compiler + const finalOptions = { + source, + filename: this.resourcePath, + compiler, + compilerOptions, + // allow customizing behavior of vue-template-es2015-compiler + transpileOptions: options.transpileOptions, + transformAssetUrls: options.transformAssetUrls || true, + isProduction, + isFunctional, + optimizeSSR: isServer && options.optimizeSSR !== false, + prettify: options.prettify + } + + const compiled = compileTemplate(finalOptions) + + // tips + if (compiled.tips && compiled.tips.length) { + compiled.tips.forEach(tip => { + loaderContext.emitWarning(typeof tip === 'object' ? tip.msg : tip) + }) + } + + // errors + if (compiled.errors && compiled.errors.length) { + // 2.6 compiler outputs errors as objects with range + if (compiler.generateCodeFrame && finalOptions.compilerOptions.outputSourceRange) { + // TODO account for line offset in case template isn't placed at top + // of the file + loaderContext.emitError( + `\n\n Errors compiling template:\n\n` + + compiled.errors.map(({ msg, start, end }) => { + const frame = compiler.generateCodeFrame(source, start, end) + return ` ${msg}\n\n${pad(frame)}` + }).join(`\n\n`) + + '\n' + ) + } else { + loaderContext.emitError( + `\n Error compiling template:\n${pad(compiled.source)}\n` + + compiled.errors.map(e => ` - ${e}`).join('\n') + + '\n' + ) + } + } + + const { code } = compiled + + if(query.recyclable) {// fixed by xxxxxx + return code + `\nexport { render, recyclableRender, staticRenderFns }` + } + // finish with ESM exports + return code + `\nexport { render, staticRenderFns }` +} + +function pad (source) { + return source + .split(/\r?\n/) + .map(line => ` ${line}`) + .join('\n') +} diff --git a/packages/vue-cli-plugin-hbuilderx/packages/weex-template-compiler/build.js b/packages/vue-cli-plugin-hbuilderx/packages/weex-template-compiler/build.js index be29e6528c7317d6212ad34e91584d8a7ca9a6e5..bab314c1f9bc1dcd797e7c62ed6129fe51297118 100644 --- a/packages/vue-cli-plugin-hbuilderx/packages/weex-template-compiler/build.js +++ b/packages/vue-cli-plugin-hbuilderx/packages/weex-template-compiler/build.js @@ -4683,7 +4683,7 @@ function postTransformComponentRoot (el) { /* */ -function postTransformRef (el, options) { +function postTransformRef (el) { if (el.ref) { addAttr(el, 'ref', el.ref); delete el.ref; diff --git a/src/core/view/bridge/subscribe/index.js b/src/core/view/bridge/subscribe/index.js index ed58a32a8bd73c94476c48a96cefafdcc57cb25a..a047a87336df7504e1c616959b431db268037fd7 100644 --- a/src/core/view/bridge/subscribe/index.js +++ b/src/core/view/bridge/subscribe/index.js @@ -27,7 +27,7 @@ const passiveOptions = supportsPassive ? { function updateCssVar (vm) { if (uni.canIUse('css.var')) { const pageVm = vm.$parent.$parent - const windowTop = pageVm.showNavigationBar && pageVm.navigationBar.type !== 'transparent' ? (NAVBAR_HEIGHT + + const windowTop = pageVm.showNavigationBar && pageVm.navigationBar.type !== 'transparent' && pageVm.navigationBar.type !== 'float' ? (NAVBAR_HEIGHT + 'px') : '0px' const windowBottom = getApp().$children[0].showTabBar ? (TABBAR_HEIGHT + 'px') : '0px' @@ -74,8 +74,8 @@ export default function initSubscribe (subscribe) { const enablePageReachBottom = hasLifecycleHook(vm.$options, 'onReachBottom') const onReachBottomDistance = pageVm.onReachBottomDistance - const enableTransparentTitleNView = isPlainObject(pageVm.titleNView) && pageVm.titleNView.type === - 'transparent' + const enableTransparentTitleNView = (isPlainObject(pageVm.titleNView) && pageVm.titleNView.type === + 'transparent') || (isPlainObject(pageVm.navigationBar) && pageVm.navigationBar.type === 'transparent') if (scrollListener) { document.removeEventListener('scroll', scrollListener) diff --git a/src/core/view/components/input/index.vue b/src/core/view/components/input/index.vue index 5eb2f156fcfbea6d35af92857de57290023ebaab..547fa976ac610862dd5c0a47351ab5cedd4609e2 100644 --- a/src/core/view/components/input/index.vue +++ b/src/core/view/components/input/index.vue @@ -308,7 +308,8 @@ uni-input[hidden] { height: 100%; background: none; color: inherit; - opacity: inherit; + opacity: 1; + -webkit-text-fill-color: currentcolor; font: inherit; line-height: inherit; letter-spacing: inherit; diff --git a/src/core/view/components/textarea/index.vue b/src/core/view/components/textarea/index.vue index cc6498c4692def67dcb6b123809e24e7ccdf1a1e..f424cf8f471588f16def52ab96b854fe6c1dbb25 100644 --- a/src/core/view/components/textarea/index.vue +++ b/src/core/view/components/textarea/index.vue @@ -340,7 +340,8 @@ uni-textarea[auto-height] .uni-textarea-textarea { resize: none; background: none; color: inherit; - opacity: inherit; + opacity: 1; + -webkit-text-fill-color: currentcolor; font: inherit; line-height: inherit; letter-spacing: inherit; diff --git a/src/platforms/h5/components/page/index.vue b/src/platforms/h5/components/page/index.vue index 146311b44a8cfbca9949488ec575c9f8311ba818..4a4dbecafa8906ab1022b85baa77832d9320830b 100644 --- a/src/platforms/h5/components/page/index.vue +++ b/src/platforms/h5/components/page/index.vue @@ -136,9 +136,28 @@ export default { titleImage: { type: String, default: '' + }, + transparentTitle: { + type: String, + default: 'none' + }, + titlePenetrate: { + type: String, + default: 'NO' } }, - data () { + data () { + const titleNViewTypeList = { + 'none': 'default', + 'auto': 'transparent', + 'always': 'float' + } + + const yesNoParseList = { + 'YES': true, + 'NO': false + } + const navigationBar = mergeTitleNView({ loading: false, backButton: !this.isQuit && !this.$route.meta.isQuit, // redirectTo,reLaunch时可能动态修改 meta.isQuit @@ -147,7 +166,10 @@ export default { titleText: this.navigationBarTitleText, titleImage: this.titleImage, duration: '0', - timingFunc: '' + timingFunc: '', + type: titleNViewTypeList[this.transparentTitle], + transparentTitle: this.transparentTitle, + titlePenetrate: yesNoParseList[this.titlePenetrate] }, this.titleNView) const showNavigationBar = this.navigationStyle === 'default' && this.titleNView diff --git a/src/platforms/h5/components/page/pageHead.vue b/src/platforms/h5/components/page/pageHead.vue index 32b4b5770b32385f176b1d94a31002575009fa7d..d1ec0cf2b415eefd352d8e8022ed50e55d159dfb 100644 --- a/src/platforms/h5/components/page/pageHead.vue +++ b/src/platforms/h5/components/page/pageHead.vue @@ -2,7 +2,7 @@
@@ -36,7 +36,7 @@ v-if="!searchInput" class="uni-page-head-bd">
-
@@ -120,6 +121,16 @@ uni-page-head .uni-page-head { color: #fff; background-color: #000; transition-property: all; +} + +uni-page-head .uni-page-head-titlePenetrate, +uni-page-head .uni-page-head-titlePenetrate .uni-page-head-bd, +uni-page-head .uni-page-head-titlePenetrate .uni-page-head-bd * { + pointer-events: none; +} + +uni-page-head .uni-page-head-titlePenetrate *{ + pointer-events: auto; } uni-page-head .uni-page-head.uni-page-head-transparent .uni-page-head-ft > div { @@ -129,6 +140,10 @@ uni-page-head .uni-page-head.uni-page-head-transparent .uni-page-head-ft > div { uni-page-head .uni-page-head ~ .uni-placeholder { width: 100%; height: 44px; +} + +uni-page-head .uni-placeholder-titlePenetrate{ + pointer-events: none; } uni-page-head .uni-page-head * { @@ -277,7 +292,7 @@ uni-page-head .uni-page-head__title .uni-loading { uni-page-head .uni-page-head__title .uni-page-head__title_image { width: auto; - height: 20px; + height: 26px; vertical-align: middle; } @@ -335,7 +350,7 @@ export default { type: { default: 'default', validator (value) { - return ['default', 'transparent'].indexOf(value) !== -1 + return ['default', 'transparent', 'float'].indexOf(value) !== -1 } }, coverage: { @@ -357,6 +372,16 @@ export default { titleImage: { type: String, default: '' + }, + transparentTitle: { + default: 'none', + validator (value) { + return ['none', 'auto', 'always'].indexOf(value) !== -1 + } + }, + titlePenetrate: { + type: Boolean, + default: false } }, data () { diff --git a/src/platforms/h5/components/page/transparent.js b/src/platforms/h5/components/page/transparent.js index acfc895c064bd67b64cf740e1ca97217ba5f543a..b4a169affda99f413c447a3e92a4692af15e1afa 100644 --- a/src/platforms/h5/components/page/transparent.js +++ b/src/platforms/h5/components/page/transparent.js @@ -6,7 +6,7 @@ export default { mounted () { if (this.type === 'transparent') { const transparentElemStyle = this.$el.querySelector('.uni-page-head-transparent').style - const titleElem = this.$el.querySelector('.uni-page-head__title') + // const titleElem = this.$el.querySelector('.uni-page-head__title') const iconElems = this.$el.querySelectorAll('.uni-btn-icon') const iconElemsStyles = [] const textColor = this.textColor @@ -40,9 +40,10 @@ export default { } this._A = alpha // TODO 暂时仅处理背景色 - if (titleElem) { - titleElem.style.opacity = alpha - } + // 对齐支付宝小程序,标题不透明渐变 + // if (titleElem) { + // titleElem.style.opacity = alpha + // } transparentElemStyle.backgroundColor = `rgba(${this._R},${this._G},${this._B},${alpha})` borderRadiusElemsStyles.forEach(function (borderRadiusElemStyle, index) { let oldColor = oldColors[index] @@ -52,17 +53,31 @@ export default { borderRadiusElemStyle.backgroundColor = `rgba(${rgba})` }) }) + } else if (this.transparentTitle === 'always') { + const iconElems = this.$el.querySelectorAll('.uni-btn-icon') + const iconElemsStyles = [] + for (let i = 0; i < iconElems.length; i++) { + iconElemsStyles.push(iconElems[i].style) + } + const borderRadiusElems = this.$el.querySelectorAll('.uni-page-head-btn') + const oldColors = [] + const borderRadiusElemsStyles = [] + for (let i = 0; i < borderRadiusElems.length; i++) { + let borderRadiusElem = borderRadiusElems[i] + oldColors.push(getComputedStyle(borderRadiusElem).backgroundColor) + borderRadiusElemsStyles.push(borderRadiusElem.style) + } } }, computed: { color () { - return this.type === 'transparent' ? '#fff' : this.textColor + return this.type === 'transparent' || this.transparentTitle === 'always' ? '#fff' : this.textColor }, offset () { return parseInt(this.coverage) }, bgColor () { - if (this.type === 'transparent') { + if (this.type === 'transparent' || this.transparentTitle === 'always') { const { r, g, diff --git a/src/platforms/h5/components/system-routes/open-location/index.vue b/src/platforms/h5/components/system-routes/open-location/index.vue index b8c1903bcbed5835c5b95d52786f2f90d9563ee8..2c8113e7fa45833fc37c9218a8e54da50ed98c49 100644 --- a/src/platforms/h5/components/system-routes/open-location/index.vue +++ b/src/platforms/h5/components/system-routes/open-location/index.vue @@ -33,9 +33,9 @@ export default { const { latitude, longitude, - scale, - name, - address + scale = 18, + name = '', + address = '' } = this.$route.query return { latitude, diff --git a/src/platforms/h5/helpers/get-window-offset.js b/src/platforms/h5/helpers/get-window-offset.js index 6137bd3af08781b8eac4f00171d169aaa765b458..b989996b0b2ff653e5ef4d940442e94e5efe1366 100644 --- a/src/platforms/h5/helpers/get-window-offset.js +++ b/src/platforms/h5/helpers/get-window-offset.js @@ -17,7 +17,7 @@ export default function getWindowOffset () { const pages = getCurrentPages() if (pages.length) { const pageVm = pages[pages.length - 1].$parent.$parent - top = pageVm.showNavigationBar && pageVm.navigationBar.type !== 'transparent' ? NAVBAR_HEIGHT : 0 + top = pageVm.showNavigationBar && (pageVm.navigationBar.type !== 'transparent' || pageVm.navigationBar.type !== 'float') ? NAVBAR_HEIGHT : 0 } const app = getApp() if (app) {