HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uniapp设置强制竖屏wgt包强制竖屏uniapp锁定屏幕竖直方向

分为三步

  1. 第一步
    uniapp 根目录下pages.json 文件中追加下面四项
    "globalStyle": {
    "pageOrientation": "portrait", //横屏配置,全局屏幕旋转设置(仅 APP/微信/QQ小程序),支持 auto / portrait / landscape
    "rpxCalcMaxDeviceWidth": 960,
    "rpxCalcBaseDeviceWidth": 375,
    "rpxCalcIncludeWidth": 750
    }
  2. 第二步
    uniapp 根目录下mainfest.json文件中追加如下配置
    distribute" : {
    "orientation" : ["portrait-primary" ] //重力感应、横竖屏配置
    }
  3. 第三步
    在你想强制横竖屏的页面的vue文件中的 onLoad 或者onShow的生命周期里面 加上如下代码即可
    //#ifdef APP-PLUS
    plus.screen.lockOrientation('portrait-primary');
    //#endif

横竖屏切换都可参照此篇文章 已本人亲自尝试,如有疑问者 可下方留言 会帮忙解答

继续阅读 »

分为三步

  1. 第一步
    uniapp 根目录下pages.json 文件中追加下面四项
    "globalStyle": {
    "pageOrientation": "portrait", //横屏配置,全局屏幕旋转设置(仅 APP/微信/QQ小程序),支持 auto / portrait / landscape
    "rpxCalcMaxDeviceWidth": 960,
    "rpxCalcBaseDeviceWidth": 375,
    "rpxCalcIncludeWidth": 750
    }
  2. 第二步
    uniapp 根目录下mainfest.json文件中追加如下配置
    distribute" : {
    "orientation" : ["portrait-primary" ] //重力感应、横竖屏配置
    }
  3. 第三步
    在你想强制横竖屏的页面的vue文件中的 onLoad 或者onShow的生命周期里面 加上如下代码即可
    //#ifdef APP-PLUS
    plus.screen.lockOrientation('portrait-primary');
    //#endif

横竖屏切换都可参照此篇文章 已本人亲自尝试,如有疑问者 可下方留言 会帮忙解答

收起阅读 »

巨坑!!!!!

bug反馈

不多说了,自己看图片。
最关键是之前还是好的,后来不知道什么时候页面数据没了,才发现这个问题,真np,之前还有一次计算可视区域的api的计算方式也改了,文档上也没更新,之前不带状态栏高度,后来带上了,这种隐藏的坑这么多,我服了

不多说了,自己看图片。
最关键是之前还是好的,后来不知道什么时候页面数据没了,才发现这个问题,真np,之前还有一次计算可视区域的api的计算方式也改了,文档上也没更新,之前不带状态栏高度,后来带上了,这种隐藏的坑这么多,我服了

Biaofun建信小程序开发工具链原理浅析

小程序

@jump-mp/cli 的安装和使用方法详见建信小程序开发文档。
在终端运行
$ jump -h
可以看到 @jump-mp/cli 中提供如下功能:
Usage: jump <command> [options]
Options:
-v, --version output the version number
-h, --help display help for command
Commands:
init initialize template for jump project
build [options] build project to be used in android or ios
update update project dependencies to the latest version
add [options] <source-name> add npm source for miniproject
construct construct installed npm source for miniproject
help [command] display help for command
init:初始化方法,用于初始化小程序项目和页面、组件;
build:用于对建信小程序进行编译打包;
update:用于更新建信小程序使用的依赖版本;
add:用于添加小程序依赖;
construct:用于构建小程序添加的依赖。
脚手架原理
在上一节中,已经介绍了 @jump-mp/cli 的基本功能。本节将对脚手架 @jump-mp/cli 的整体架构和技术选型进行介绍。
01
现有脚手架技术分析
目前较常用的前端开发脚手架工具有 yoeman、vue-cli 等。
yeoman 搭建项目需要提供 yoeman-generator。yoeman-generator 本质上就是有 i 个具备完整文件结构的项目样板,用户需要手动地把这些 generator 下载到本地,然后 yoeman 就会根据这些 generator 自动生成各种不同的项目。
vue-cli 提供了相当丰富的选项和设定功能,但是其本质也是从远程仓库把不同的模版拉取到本地,而并非是“本地生成“的黑科技。
综上,目前脚手架的思路大都是建立不同的样板项目,然后脚手架根据用户指令引用样板项目生成实际项目。样板项目可以内置在脚手架中,也可以部署在远程仓库。
02
技术选型及架构
为了更好地实现模版定制和功能开发,大前端团队自研了建信小程序脚手架 @jump-mp/cli。脚手架主要使用了以下技术:
node.js:整个脚手架工具的根本组成部分。
commander: 用于组织和处理命令行的输入。
webpack:用于对一些需要编译的文件进行处理。
脚手架的整体架构如下图:
在创建小程序、页面和组件时,小程序的项目、页面和组件的模版(template)都存放在依赖 jump-mp/cli-template 中。每当用户需要创建时,就通过 cli 的命令向 jump-mp/cli-template 中拉取相应的模版并下载到本地。
对于编译、构建等功能,会在后面的小节进行介绍。
最终整个 @jump-mp/cli 的脚手架文件结构如下。
├── bin
│ └── index.js
├── command
│ ├── add.js
│ ├── build.js
│ ├── create.js
│ ├── translate.js
│ └── update.js
├── node_modules
│ └── @jump-mp
│ ├── build
│ └── cli-template
│ ├── component
│ ├── page
│ └── project
└── package.json
其中 bin/index.s为入口文件,主要用 commander 来构建命令行。commander 的工作流程如下:
编译器原理
在完成小程序的开发后,需要在项目根目录下运行 jump build [option] 来对小程序进行编译打包。下面将介绍建信小程序打包过程中的编译原理。
01
小程序引擎
在《初识建信小程序引擎》一文中我们了解到,为了提升小程序的运行性能、用户体验,建信小程序采用了双线程模式,将运行环境分为视图层(view 层)和逻辑层(service 层)。其中视图层负责页面展示,逻辑层负责小程序业务逻辑。视图层和逻辑层分别由 2 个线程管理:
视图层的界面使用了 WebView 进行渲染,视图层使用 Vuejs 作为 MVVM 框架;
逻辑层采用 JsCore 线程运行 JavaScript 脚本。
同时,视图层线程和逻辑层线程通信会经由建信客户端(Native 层)做中转,逻辑层发送网络请求也经由 Native 层转发,Native 层也会渲染一些原生的组件、被小程序调用一些原生的 API。
综上,编译器的主要功能是将小程序代码进行编译,将 view 层、service 层、native 层三个部分各自需要的代码进行提取、转换、整合,最终打包成一个可以在建信客户端运行的小程序。
02
技术选型
编译器主要使用了以下技术:
node.js:整个脚手架工具的根本组成部分。
gulp:基于流的自动化构建工具。
babel相关:用于构建 js 代码的 ast 树、修改 js 代码、编译 js 代码。
vue-template-compiler:用于构建 html 代码的 ast 树,修改 html 代码、编译 html 代码。
postcss:用于修改、编译 css 代码。
webpack:用于对一些需要编译的文件进行处理。
03
编译器原理
编译器在工作的过程中,会经历预处理、编译、打包三个步骤,具体流程如下:
下面将详细描述编译原理和流程。
(1)mxml—>使用 vue 框架的 html
对于页面/组件的 mxml 页面,编译器做了如下处理:
首先,mxml 会被解析为一颗 ast 抽象语法树
然后,编译器会遍历该 ast 语法树,将组件名转为小程序内置组件名(例:button->mp-button),将建信小程序语法标签转为 vue 语法标签(例:mp:if->v-if)。
最后,遍历该 ast 抽象语法树,将 ast 转为使用 vue 框架的 html 代码。
(2)mcss—>css
将 mcss 转为 css 主要做了设备视图分辨率适配,将 rpx 单位转为 vw。
(3)使用 vue 框架的 html—>使用 vue 框架的 page.view.js
在生成了 html 中间态文件“使用 vue 框架的 html” 后,还需要生成一个符合 vue 框架要求的 js 文件,然后将其组合到一个 html 文件(及 page.html)中,该文件才可在使用了 vue 引擎的视图层中被加载,因此我们需要一个这样的 html 文件。举例说明:
jump 小程序:
mxml
<view>
<view>{{title}}</view>
<button bindtap="clickMe">请点击换标题</button>
</view>
js
Page({
data: {
title: 'Hello World',
},
//事件处理函数
clickMe: function() {
this.setData({
title: '你好,世界'
})
}
})
那么转换之后的 vue 页面应该是:
<template>
<mp-view>
<mp-view>{{title}}</mp-view>
<mp-button @click="clickMe">请点击换标题</mp-button>
<mp-view>
<template>
<script>
export default {
data(){
return {
title: '',
}
}
}
</script>
这里 data 中的变量名不是通过解析 page.js 得到的,因为开发者在编写 page.js 时是没有要求固定格式的,因此无法通过抽象代码树解析的方式拿到 data 的参数,所以这里 data 的变量名是通过解析 html 表达式拿到的。
而没有将 data 中的数据值和 method 方法写到 html 页面中,是因为这部分应由 service 逻辑层处理,view 层只需声明变量名即可。
最终再通过 vue 生成的 html 页面应为:
<html>
<head>......</head>
<body>
......
<script>
new Vue({
data() {
return {
title:""
}
},
el: "#app",
template:"<template><mp-view><mp-view>{{title}}</mp-view><mp-button @click="clickMe">请点击换标题</mp-button> <mp-view><template>"
});
</script>
</body>
</html>
如要生成上述页面,首先我们需要拿到data中的变量名,使用的方法是,通过解析 html 中的表达式来获得变量名。
然后则是构建 html 页面中的 js 代码,这里使用 babel 去构建一个 js 的 ast 抽象语法树,然后向树中插入 data 和 template 的参数和值。
由于考虑到随着页面功能的增多以及版本的迭代,直接构建目标态代码,在未来版本发生迭代时很可能会导致编译逻辑会跟随修改。为了解决这一问题,我们需要区分出目标态代码的不变部分和可变部分。把不变部分抽象为源对象,把可变部分交由 runtime 运行时框架处理。这样只需要在 rumtime 层做版本迭代而不需要编译器修改。
为了提高加载速度,我们在编译阶段做了预处理,把原本在运行时处理的渲染模版提前展开为真实的虚拟节点树。
所以本步骤整体的工作流程如下图:
最终生成的 page.view.js 应为:
let app = window.$$makeVueComponent({
data() {
return {
title: ""
};
},
el: "#app",
render: function anonymous() {
with(this){return _c('mp-view',[_c('mp-view',[_c('mp-view',[_v(_s(title))]),_v(" "),_c('mp-button',{on:{"click":function($event){return eventHandlerProxy('clickMe',$event)}}},[_v("请点击换标题")])],1)],1)}
},
staticRenderFns: []
});
new Vue(app);
(4)页面(page)中引入的组件(component)的处理
由于视图 view 层在加载页面时只会去加载该页面的 html,因此需要在编译页面时将页面中引入的组件(component)也编译进 html 中。这里的编译流程如下:
编译器会先读取所编译的 page 的 json 文件,如果 json 文件中引入了组件,则将编译后的组件的 js 加入到 page 的 html 中。然后再去读取改组件的 json 文件,查看改组件是否引入了其他组件,一直递归循环,直至所有组件都被编译进 html 文件为止。对于每个页面重复引入的组件,则只编入一次。
(5)page.js 的编译
在处理需要在 service 逻辑层运行的 page.js 时,我们不会去改变文件的代码,只是对 page.js 用 webpack 做编译打包,然后汇总到 app-service.js 文件中。
构建 npm 依赖
建信小程序支持引入第三方 npm 依赖。这里不再对 npm 的功能进行介绍,可以参考官方 npm 文档。
01
使用方法
建信小程序引入 npm 依赖,需要添加依赖和构建依赖两个步骤。
其中,构建依赖的目的是,将安装在 node_modules 下的依赖进行编译构建,然后生成到项目根目录下的 npm_miniprogram 文件夹下,以供小程序在开发过程中进行引入。
02
构建原理
在使用 npm 依赖时需要构建依赖,是因为在小程序编译时,无法在未指定路径的情况下将 require 的 node_modules 下的依赖编译进去,所以需要构建这个步骤,将依赖进行预编译,然后统一到一个目录下。
npm 依赖的构建原理如下图所示:
首先会读取项目根目录下的package.json, 如果 devDependencies/dependencies 不为空,则小程序中有使用 npm 依赖,需要构建。
在 node_modules 中找到小程序引入的依赖,查看该依赖是否指明小程序的引入入口(miniprogram_dist 目录),如果有则直接将其复制到 miniprogram_npm 路径下,如果没有则使用 webpack 由 main 入口进行编译,编译结果保存到 miniprogram_npm 路径。
对构建完成的 npm 依赖 重复第一步的步骤,直到所有依赖及依赖的依赖构建完成。

文章来源:Biaofun标梵互动(https://www.biaofun.com/)

继续阅读 »

@jump-mp/cli 的安装和使用方法详见建信小程序开发文档。
在终端运行
$ jump -h
可以看到 @jump-mp/cli 中提供如下功能:
Usage: jump <command> [options]
Options:
-v, --version output the version number
-h, --help display help for command
Commands:
init initialize template for jump project
build [options] build project to be used in android or ios
update update project dependencies to the latest version
add [options] <source-name> add npm source for miniproject
construct construct installed npm source for miniproject
help [command] display help for command
init:初始化方法,用于初始化小程序项目和页面、组件;
build:用于对建信小程序进行编译打包;
update:用于更新建信小程序使用的依赖版本;
add:用于添加小程序依赖;
construct:用于构建小程序添加的依赖。
脚手架原理
在上一节中,已经介绍了 @jump-mp/cli 的基本功能。本节将对脚手架 @jump-mp/cli 的整体架构和技术选型进行介绍。
01
现有脚手架技术分析
目前较常用的前端开发脚手架工具有 yoeman、vue-cli 等。
yeoman 搭建项目需要提供 yoeman-generator。yoeman-generator 本质上就是有 i 个具备完整文件结构的项目样板,用户需要手动地把这些 generator 下载到本地,然后 yoeman 就会根据这些 generator 自动生成各种不同的项目。
vue-cli 提供了相当丰富的选项和设定功能,但是其本质也是从远程仓库把不同的模版拉取到本地,而并非是“本地生成“的黑科技。
综上,目前脚手架的思路大都是建立不同的样板项目,然后脚手架根据用户指令引用样板项目生成实际项目。样板项目可以内置在脚手架中,也可以部署在远程仓库。
02
技术选型及架构
为了更好地实现模版定制和功能开发,大前端团队自研了建信小程序脚手架 @jump-mp/cli。脚手架主要使用了以下技术:
node.js:整个脚手架工具的根本组成部分。
commander: 用于组织和处理命令行的输入。
webpack:用于对一些需要编译的文件进行处理。
脚手架的整体架构如下图:
在创建小程序、页面和组件时,小程序的项目、页面和组件的模版(template)都存放在依赖 jump-mp/cli-template 中。每当用户需要创建时,就通过 cli 的命令向 jump-mp/cli-template 中拉取相应的模版并下载到本地。
对于编译、构建等功能,会在后面的小节进行介绍。
最终整个 @jump-mp/cli 的脚手架文件结构如下。
├── bin
│ └── index.js
├── command
│ ├── add.js
│ ├── build.js
│ ├── create.js
│ ├── translate.js
│ └── update.js
├── node_modules
│ └── @jump-mp
│ ├── build
│ └── cli-template
│ ├── component
│ ├── page
│ └── project
└── package.json
其中 bin/index.s为入口文件,主要用 commander 来构建命令行。commander 的工作流程如下:
编译器原理
在完成小程序的开发后,需要在项目根目录下运行 jump build [option] 来对小程序进行编译打包。下面将介绍建信小程序打包过程中的编译原理。
01
小程序引擎
在《初识建信小程序引擎》一文中我们了解到,为了提升小程序的运行性能、用户体验,建信小程序采用了双线程模式,将运行环境分为视图层(view 层)和逻辑层(service 层)。其中视图层负责页面展示,逻辑层负责小程序业务逻辑。视图层和逻辑层分别由 2 个线程管理:
视图层的界面使用了 WebView 进行渲染,视图层使用 Vuejs 作为 MVVM 框架;
逻辑层采用 JsCore 线程运行 JavaScript 脚本。
同时,视图层线程和逻辑层线程通信会经由建信客户端(Native 层)做中转,逻辑层发送网络请求也经由 Native 层转发,Native 层也会渲染一些原生的组件、被小程序调用一些原生的 API。
综上,编译器的主要功能是将小程序代码进行编译,将 view 层、service 层、native 层三个部分各自需要的代码进行提取、转换、整合,最终打包成一个可以在建信客户端运行的小程序。
02
技术选型
编译器主要使用了以下技术:
node.js:整个脚手架工具的根本组成部分。
gulp:基于流的自动化构建工具。
babel相关:用于构建 js 代码的 ast 树、修改 js 代码、编译 js 代码。
vue-template-compiler:用于构建 html 代码的 ast 树,修改 html 代码、编译 html 代码。
postcss:用于修改、编译 css 代码。
webpack:用于对一些需要编译的文件进行处理。
03
编译器原理
编译器在工作的过程中,会经历预处理、编译、打包三个步骤,具体流程如下:
下面将详细描述编译原理和流程。
(1)mxml—>使用 vue 框架的 html
对于页面/组件的 mxml 页面,编译器做了如下处理:
首先,mxml 会被解析为一颗 ast 抽象语法树
然后,编译器会遍历该 ast 语法树,将组件名转为小程序内置组件名(例:button->mp-button),将建信小程序语法标签转为 vue 语法标签(例:mp:if->v-if)。
最后,遍历该 ast 抽象语法树,将 ast 转为使用 vue 框架的 html 代码。
(2)mcss—>css
将 mcss 转为 css 主要做了设备视图分辨率适配,将 rpx 单位转为 vw。
(3)使用 vue 框架的 html—>使用 vue 框架的 page.view.js
在生成了 html 中间态文件“使用 vue 框架的 html” 后,还需要生成一个符合 vue 框架要求的 js 文件,然后将其组合到一个 html 文件(及 page.html)中,该文件才可在使用了 vue 引擎的视图层中被加载,因此我们需要一个这样的 html 文件。举例说明:
jump 小程序:
mxml
<view>
<view>{{title}}</view>
<button bindtap="clickMe">请点击换标题</button>
</view>
js
Page({
data: {
title: 'Hello World',
},
//事件处理函数
clickMe: function() {
this.setData({
title: '你好,世界'
})
}
})
那么转换之后的 vue 页面应该是:
<template>
<mp-view>
<mp-view>{{title}}</mp-view>
<mp-button @click="clickMe">请点击换标题</mp-button>
<mp-view>
<template>
<script>
export default {
data(){
return {
title: '',
}
}
}
</script>
这里 data 中的变量名不是通过解析 page.js 得到的,因为开发者在编写 page.js 时是没有要求固定格式的,因此无法通过抽象代码树解析的方式拿到 data 的参数,所以这里 data 的变量名是通过解析 html 表达式拿到的。
而没有将 data 中的数据值和 method 方法写到 html 页面中,是因为这部分应由 service 逻辑层处理,view 层只需声明变量名即可。
最终再通过 vue 生成的 html 页面应为:
<html>
<head>......</head>
<body>
......
<script>
new Vue({
data() {
return {
title:""
}
},
el: "#app",
template:"<template><mp-view><mp-view>{{title}}</mp-view><mp-button @click="clickMe">请点击换标题</mp-button> <mp-view><template>"
});
</script>
</body>
</html>
如要生成上述页面,首先我们需要拿到data中的变量名,使用的方法是,通过解析 html 中的表达式来获得变量名。
然后则是构建 html 页面中的 js 代码,这里使用 babel 去构建一个 js 的 ast 抽象语法树,然后向树中插入 data 和 template 的参数和值。
由于考虑到随着页面功能的增多以及版本的迭代,直接构建目标态代码,在未来版本发生迭代时很可能会导致编译逻辑会跟随修改。为了解决这一问题,我们需要区分出目标态代码的不变部分和可变部分。把不变部分抽象为源对象,把可变部分交由 runtime 运行时框架处理。这样只需要在 rumtime 层做版本迭代而不需要编译器修改。
为了提高加载速度,我们在编译阶段做了预处理,把原本在运行时处理的渲染模版提前展开为真实的虚拟节点树。
所以本步骤整体的工作流程如下图:
最终生成的 page.view.js 应为:
let app = window.$$makeVueComponent({
data() {
return {
title: ""
};
},
el: "#app",
render: function anonymous() {
with(this){return _c('mp-view',[_c('mp-view',[_c('mp-view',[_v(_s(title))]),_v(" "),_c('mp-button',{on:{"click":function($event){return eventHandlerProxy('clickMe',$event)}}},[_v("请点击换标题")])],1)],1)}
},
staticRenderFns: []
});
new Vue(app);
(4)页面(page)中引入的组件(component)的处理
由于视图 view 层在加载页面时只会去加载该页面的 html,因此需要在编译页面时将页面中引入的组件(component)也编译进 html 中。这里的编译流程如下:
编译器会先读取所编译的 page 的 json 文件,如果 json 文件中引入了组件,则将编译后的组件的 js 加入到 page 的 html 中。然后再去读取改组件的 json 文件,查看改组件是否引入了其他组件,一直递归循环,直至所有组件都被编译进 html 文件为止。对于每个页面重复引入的组件,则只编入一次。
(5)page.js 的编译
在处理需要在 service 逻辑层运行的 page.js 时,我们不会去改变文件的代码,只是对 page.js 用 webpack 做编译打包,然后汇总到 app-service.js 文件中。
构建 npm 依赖
建信小程序支持引入第三方 npm 依赖。这里不再对 npm 的功能进行介绍,可以参考官方 npm 文档。
01
使用方法
建信小程序引入 npm 依赖,需要添加依赖和构建依赖两个步骤。
其中,构建依赖的目的是,将安装在 node_modules 下的依赖进行编译构建,然后生成到项目根目录下的 npm_miniprogram 文件夹下,以供小程序在开发过程中进行引入。
02
构建原理
在使用 npm 依赖时需要构建依赖,是因为在小程序编译时,无法在未指定路径的情况下将 require 的 node_modules 下的依赖编译进去,所以需要构建这个步骤,将依赖进行预编译,然后统一到一个目录下。
npm 依赖的构建原理如下图所示:
首先会读取项目根目录下的package.json, 如果 devDependencies/dependencies 不为空,则小程序中有使用 npm 依赖,需要构建。
在 node_modules 中找到小程序引入的依赖,查看该依赖是否指明小程序的引入入口(miniprogram_dist 目录),如果有则直接将其复制到 miniprogram_npm 路径下,如果没有则使用 webpack 由 main 入口进行编译,编译结果保存到 miniprogram_npm 路径。
对构建完成的 npm 依赖 重复第一步的步骤,直到所有依赖及依赖的依赖构建完成。

文章来源:Biaofun标梵互动(https://www.biaofun.com/)

收起阅读 »

app点击返回按钮出现提示框,确定的时候才返回

返回按键 返回 uniapp

不加flag变量控制的话,点击返回,会死循环弹出提示框。

flag: true//是否弹出返回提示框  

        onBackPress() {  
            console.log("点击了返回");  
            if (this.flag) {  
                uni.showModal({  
                    title: "温馨提示",  
                    content: "是否确定退出?",  
                    success: (res) => {  
                        if (res.confirm) {  
                            console.log("确定返回");  
                            this.flag = false  
                            uni.navigateBack({  
                                delta: 1  
                            })  
                            return true  
                        } else {  
                            this.flag = true  
                            console.log("取消");  
                            return true  
                        }  
                    }  
                })  
                return true  
            }else{  
                return false  
            }  
        },
继续阅读 »

不加flag变量控制的话,点击返回,会死循环弹出提示框。

flag: true//是否弹出返回提示框  

        onBackPress() {  
            console.log("点击了返回");  
            if (this.flag) {  
                uni.showModal({  
                    title: "温馨提示",  
                    content: "是否确定退出?",  
                    success: (res) => {  
                        if (res.confirm) {  
                            console.log("确定返回");  
                            this.flag = false  
                            uni.navigateBack({  
                                delta: 1  
                            })  
                            return true  
                        } else {  
                            this.flag = true  
                            console.log("取消");  
                            return true  
                        }  
                    }  
                })  
                return true  
            }else{  
                return false  
            }  
        },
收起阅读 »

通告栏最简使用方案

多行上下轮播 使用swiper 代码如图
单行轮播可以使用css动画来实现
.notice {
position: absolute;
display: block;
white-space: nowrap;
padding-left: 100%;
animation: notice 10s 0s linear infinite both;
animation-play-state: paused;
/ 设置时间 /
animation-duration: 10s;
animation-play-state: running;
animation-delay: -3.51s;
}

@keyframes notice {  
    100% {  
        transform: translate3d(-100%, 0, 0);  
    }  
}
继续阅读 »

多行上下轮播 使用swiper 代码如图
单行轮播可以使用css动画来实现
.notice {
position: absolute;
display: block;
white-space: nowrap;
padding-left: 100%;
animation: notice 10s 0s linear infinite both;
animation-play-state: paused;
/ 设置时间 /
animation-duration: 10s;
animation-play-state: running;
animation-delay: -3.51s;
}

@keyframes notice {  
    100% {  
        transform: translate3d(-100%, 0, 0);  
    }  
}
收起阅读 »

判断进入登录页还是首页

登录状态

页面初始化的时候,未登录跳转到登录页的话,会闪一下pages.json里的第一个首页。

而使用首页v-if来切换登录页面模板的话,tabbar又会闪一下。哪怕是在app.vue里写了uni.hideTabbar(),还是会闪。

最终只能在pages.json第一项搞个空白页,然后redirect到登录页了,看起来自然一点。

(我测试的环境是微信小程序,使用的hbuilderX是2.9.8)

继续阅读 »

页面初始化的时候,未登录跳转到登录页的话,会闪一下pages.json里的第一个首页。

而使用首页v-if来切换登录页面模板的话,tabbar又会闪一下。哪怕是在app.vue里写了uni.hideTabbar(),还是会闪。

最终只能在pages.json第一项搞个空白页,然后redirect到登录页了,看起来自然一点。

(我测试的环境是微信小程序,使用的hbuilderX是2.9.8)

收起阅读 »

vue nvue canvas video的吐槽

商品详情有个canvas画海报的功能,一开始没什么的
一天商品详情被要求支持短视频video,也没啥的
video在vue swiper中不能轮播,嗯开始有问题了
官方的建议是使用nvue
切换了一天,vue swiper video很完美
开心。。。。。
下班。。。。。
。。。。。。。
半路
测试说APP无法生成海报
卧槽,nvue不支持canvas
so,我现在又在电脑面前找解决方案
兄弟们
九九孩子

官方的NvueCanvasDemo不是我想要的

看来只能麻烦后台了

继续阅读 »

商品详情有个canvas画海报的功能,一开始没什么的
一天商品详情被要求支持短视频video,也没啥的
video在vue swiper中不能轮播,嗯开始有问题了
官方的建议是使用nvue
切换了一天,vue swiper video很完美
开心。。。。。
下班。。。。。
。。。。。。。
半路
测试说APP无法生成海报
卧槽,nvue不支持canvas
so,我现在又在电脑面前找解决方案
兄弟们
九九孩子

官方的NvueCanvasDemo不是我想要的

看来只能麻烦后台了

收起阅读 »

关于新版本canvasGetImageData报错的解决方法

uniapp

蓝牙打印一直用到uni.canvasGetImageData生成画布,更新新版本后一直报错,现在使用uni.canvasPutImageData替代

               uni.canvasPutImageData({  
                  canvasId: 'prite_area_canvas',  
                  x: 0,  
                  y: 0,  
                  width: canvasWidth,  
                  height: canvasHeight,  
                  data: command.getData(),  
                  success: function(res) {  
                    console.log('success')  
                    command.setBitmap(res)  
                  },  
                  fail:function(){  
                    console.log('fail')  
                  },  
                  complete: function() {  
                    // command.setPrintAndFeedRow(3);  
                    console.log('complete')  
                    that.prepareSend(command.getData());  
                  }  
                })
继续阅读 »

蓝牙打印一直用到uni.canvasGetImageData生成画布,更新新版本后一直报错,现在使用uni.canvasPutImageData替代

               uni.canvasPutImageData({  
                  canvasId: 'prite_area_canvas',  
                  x: 0,  
                  y: 0,  
                  width: canvasWidth,  
                  height: canvasHeight,  
                  data: command.getData(),  
                  success: function(res) {  
                    console.log('success')  
                    command.setBitmap(res)  
                  },  
                  fail:function(){  
                    console.log('fail')  
                  },  
                  complete: function() {  
                    // command.setPrintAndFeedRow(3);  
                    console.log('complete')  
                    that.prepareSend(command.getData());  
                  }  
                })
收起阅读 »

Vue.js自定义垂直/水平滚动条组件|vue模拟滚动条

vue.js

介绍

VScroll滚动条 基于vuejs2.x构建的美化XY轴滚动条组件。支持原生滚动条、鼠标移出是否隐藏滚动条、自定义滚动条尺寸、颜色及层级等功能。拥有漂亮且流畅的滚动体验!

vue.js仿饿了么滚动条组件|vue自定义滚动条

img
img

参数配置

props: {  
    // 是否显示原生滚动条  
    native: Boolean,  
    // 是否自动隐藏滚动条  
    autohide: Boolean,  
    // 滚动条尺寸  
    size: { type: [Number, String], default: '' },  
    // 滚动条颜色  
    color: String,  
    // 滚动条层级  
    zIndex: null  
},

img

快速引入

在main.js中引入组件。

import VScroll from './components/vscroll';  
Vue.use(VScroll);

使用组件

<!-- 支持原生滚动条 -->  
<v-scroll native>  
    <img src="https://cn.vuejs.org/images/logo.png" />  
    <p>这里是自定义内容。这里是自定义内容。这里是自定义内容。</p>  
</v-scroll>  

<!-- 参数配置 -->  
<v-scroll autohide size="15" color="#00a1e0" zIndex="2021">  
    <img src="https://cn.vuejs.org/images/logo.png" />  
    <p>这里是自定义内容。这里是自定义内容。这里是自定义内容。</p>  
</v-scroll>

img

img

实现过程

// vscroll模板  
<template>  
  <div class="vui__scrollbar" ref="ref__box" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" v-resize="handleResize">  
    <div :class="['vscroll__wrap', {native: native}]" ref="ref__wrap" @scroll="handleScroll">  
      <div class="vscroll__view" v-resize="handleResize"><slot /></div>  
    </div>  
    <!-- //水平|垂直滚动条 -->  
    <div :class="['vscroll__bar vertical', {ishide: !isShow}]" @mousedown="handleClickTrack($event, 0)" :style="{'width': parseInt(size)>=0 ? parseInt(size)+'px' : '', 'z-index': parseInt(zIndex)>=0 ? parseInt(zIndex) : ''}">  
      <div class="vscroll__thumb" ref="ref__barY" :style="{'background': color, 'height': barHeight+'px'}" @mousedown="handleDragThumb($event, 0)"></div>  
    </div>  
    <div :class="['vscroll__bar horizontal', {ishide: !isShow}]" @mousedown="handleClickTrack($event, 1)" :style="{'height': parseInt(size)>=0 ? parseInt(size)+'px' : '', 'z-index': parseInt(zIndex)>=0 ? parseInt(zIndex) : ''}">  
      <div class="vscroll__thumb" ref="ref__barX" :style="{'background': color, 'width': barWidth+'px'}" @mousedown="handleDragThumb($event, 1)"></div>  
    </div>  
  </div>  
</template>
/**  
 * @Desc     VueJs虚拟滚动条组件VScroll  
<script>  
  import domUtils from './utils/dom'  
  export default {  
    props: {  
      // 显示原生滚动条  
      native: Boolean,  
      // 自动隐藏滚动条  
      autohide: Boolean,  
      // 滚动条尺寸  
      size: { type: [Number, String], default: '' },  
      // 滚动条颜色  
      color: String,  
      // 滚动条层级  
      zIndex: null  
    },  
    data() {  
      return {  
        barWidth: 0,            // 滚动条宽度  
        barHeight: 0,           // 滚动条高度  
        ratioX: 1,              // 滚动条水平偏移率  
        ratioY: 1,              // 滚动条垂直偏移率  
        isTaped: false,         // 鼠标光标是否按住滚动条  
        isHover: false,         // 鼠标光标是否悬停在滚动区  
        isShow: !this.autohide, // 是否显示滚动条  
      }  
    },  
    mounted() {  
      this.$ref__box = this.$refs.ref__box  
      this.$ref__wrap = this.$refs.ref__wrap  
      this.$ref__barY = this.$refs.ref__barY  
      this.$ref__barX = this.$refs.ref__barX  
      this.$nextTick(this.updated)  
    },  
    // ...  
    methods: {  
      // 鼠标移入  
      handleMouseEnter() {  
        this.isHover = true  
        this.isShow = true  
        this.updated()  
      },  

      // 鼠标移出  
      handleMouseLeave() {  
        this.isHover = false  
        this.isShow = false  
      },  

      // 拖动滚动条  
      handleDragThumb(e, index) {  
        let _this = this  
        this.isTaped = true  
        let c = {}  

        domUtils.isIE() ? (e.returnValue = false, e.cancelBubble = true) : (e.stopPropagation(), e.preventDefault())  
        document.onselectstart = () => false  

        if(index == 0) {  
          c.dragY = true  
          c.clientY = e.clientY  
        }else {  
          c.dragX = true  
          c.clientX = e.clientX  
        }  

        domUtils.on(document, 'mousemove', function(evt) {  
          if(_this.isTaped) {  
            if(c.dragY) {  
              _this.$ref__wrap.scrollTop += (evt.clientY - c.clientY) * _this.ratioY  
              _this.$ref__barY.style.transform = `translateY(${_this.$ref__wrap.scrollTop / _this.ratioY}px)`  
              c.clientY = evt.clientY  
            }  
            if(c.dragX) {  
              _this.$ref__wrap.scrollLeft += (evt.clientX - c.clientX) * _this.ratioX  
              _this.$ref__barX.style.transform = `translateX(${_this.$ref__wrap.scrollLeft / _this.ratioX}px)`  
              c.clientX = evt.clientX  
            }  
          }  
        })  
        domUtils.on(document, 'mouseup', function() {  
          _this.isTaped = false  

          document.onmouseup = null;  
          document.onselectstart = null  
        })  
      },  

      // 滚动槽  
      handleClickTrack(e, index) {  
        console.log(index)  
      },  

      // 更新滚动  
      updated() {  
        if(this.native) return  

        // 垂直滚动条  
        if(this.$ref__wrap.scrollHeight > this.$ref__wrap.offsetHeight) {  
          this.barHeight = this.$ref__box.offsetHeight **2 / this.$ref__wrap.scrollHeight  
          this.ratioY = (this.$ref__wrap.scrollHeight - this.$ref__box.offsetHeight) / (this.$ref__box.offsetHeight - this.barHeight)  
          this.$ref__barY.style.transform = `translateY(${this.$ref__wrap.scrollTop / this.ratioY}px)`  
        }else {  
          this.barHeight = 0  
          this.$ref__barY.style.transform = ''  
          this.$ref__wrap.style.marginRight = ''  
        }  

        // 水平滚动条  
        ...  
      },  

      handleResize() {  
        // 更新滚动条状态  
      },  

      // ...  
    }  
  }  
</script>

vue中directives指令函数监听DOM变化。

// 监听元素/DOM尺寸变化  
directives: {  
    'resize': {  
        bind: function(el, binding) {  
            let width = '', height = '';  
            function get() {  
            const elStyle = el.currentStyle ? el.currentStyle : document.defaultView.getComputedStyle(el, null);  
            if (width !== elStyle.width || height !== elStyle.height) {  
                binding.value({width, height});  
            }  
            width = elStyle.width;  
            height = elStyle.height;  
            }  
            el.__vueReize__ = setInterval(get, 16);  
        },  
        unbind: function(el) {  
            clearInterval(el.__vueReize__);  
        }  
    }  
}

img

img

好了,今天就分享到这里。希望大家能喜欢哈!

基于vue.js网页弹窗组件|vue自定义对话框VLayer

img

链接:https://juejin.cn/post/6901103494971785223/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

继续阅读 »

介绍

VScroll滚动条 基于vuejs2.x构建的美化XY轴滚动条组件。支持原生滚动条、鼠标移出是否隐藏滚动条、自定义滚动条尺寸、颜色及层级等功能。拥有漂亮且流畅的滚动体验!

vue.js仿饿了么滚动条组件|vue自定义滚动条

img
img

参数配置

props: {  
    // 是否显示原生滚动条  
    native: Boolean,  
    // 是否自动隐藏滚动条  
    autohide: Boolean,  
    // 滚动条尺寸  
    size: { type: [Number, String], default: '' },  
    // 滚动条颜色  
    color: String,  
    // 滚动条层级  
    zIndex: null  
},

img

快速引入

在main.js中引入组件。

import VScroll from './components/vscroll';  
Vue.use(VScroll);

使用组件

<!-- 支持原生滚动条 -->  
<v-scroll native>  
    <img src="https://cn.vuejs.org/images/logo.png" />  
    <p>这里是自定义内容。这里是自定义内容。这里是自定义内容。</p>  
</v-scroll>  

<!-- 参数配置 -->  
<v-scroll autohide size="15" color="#00a1e0" zIndex="2021">  
    <img src="https://cn.vuejs.org/images/logo.png" />  
    <p>这里是自定义内容。这里是自定义内容。这里是自定义内容。</p>  
</v-scroll>

img

img

实现过程

// vscroll模板  
<template>  
  <div class="vui__scrollbar" ref="ref__box" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" v-resize="handleResize">  
    <div :class="['vscroll__wrap', {native: native}]" ref="ref__wrap" @scroll="handleScroll">  
      <div class="vscroll__view" v-resize="handleResize"><slot /></div>  
    </div>  
    <!-- //水平|垂直滚动条 -->  
    <div :class="['vscroll__bar vertical', {ishide: !isShow}]" @mousedown="handleClickTrack($event, 0)" :style="{'width': parseInt(size)>=0 ? parseInt(size)+'px' : '', 'z-index': parseInt(zIndex)>=0 ? parseInt(zIndex) : ''}">  
      <div class="vscroll__thumb" ref="ref__barY" :style="{'background': color, 'height': barHeight+'px'}" @mousedown="handleDragThumb($event, 0)"></div>  
    </div>  
    <div :class="['vscroll__bar horizontal', {ishide: !isShow}]" @mousedown="handleClickTrack($event, 1)" :style="{'height': parseInt(size)>=0 ? parseInt(size)+'px' : '', 'z-index': parseInt(zIndex)>=0 ? parseInt(zIndex) : ''}">  
      <div class="vscroll__thumb" ref="ref__barX" :style="{'background': color, 'width': barWidth+'px'}" @mousedown="handleDragThumb($event, 1)"></div>  
    </div>  
  </div>  
</template>
/**  
 * @Desc     VueJs虚拟滚动条组件VScroll  
<script>  
  import domUtils from './utils/dom'  
  export default {  
    props: {  
      // 显示原生滚动条  
      native: Boolean,  
      // 自动隐藏滚动条  
      autohide: Boolean,  
      // 滚动条尺寸  
      size: { type: [Number, String], default: '' },  
      // 滚动条颜色  
      color: String,  
      // 滚动条层级  
      zIndex: null  
    },  
    data() {  
      return {  
        barWidth: 0,            // 滚动条宽度  
        barHeight: 0,           // 滚动条高度  
        ratioX: 1,              // 滚动条水平偏移率  
        ratioY: 1,              // 滚动条垂直偏移率  
        isTaped: false,         // 鼠标光标是否按住滚动条  
        isHover: false,         // 鼠标光标是否悬停在滚动区  
        isShow: !this.autohide, // 是否显示滚动条  
      }  
    },  
    mounted() {  
      this.$ref__box = this.$refs.ref__box  
      this.$ref__wrap = this.$refs.ref__wrap  
      this.$ref__barY = this.$refs.ref__barY  
      this.$ref__barX = this.$refs.ref__barX  
      this.$nextTick(this.updated)  
    },  
    // ...  
    methods: {  
      // 鼠标移入  
      handleMouseEnter() {  
        this.isHover = true  
        this.isShow = true  
        this.updated()  
      },  

      // 鼠标移出  
      handleMouseLeave() {  
        this.isHover = false  
        this.isShow = false  
      },  

      // 拖动滚动条  
      handleDragThumb(e, index) {  
        let _this = this  
        this.isTaped = true  
        let c = {}  

        domUtils.isIE() ? (e.returnValue = false, e.cancelBubble = true) : (e.stopPropagation(), e.preventDefault())  
        document.onselectstart = () => false  

        if(index == 0) {  
          c.dragY = true  
          c.clientY = e.clientY  
        }else {  
          c.dragX = true  
          c.clientX = e.clientX  
        }  

        domUtils.on(document, 'mousemove', function(evt) {  
          if(_this.isTaped) {  
            if(c.dragY) {  
              _this.$ref__wrap.scrollTop += (evt.clientY - c.clientY) * _this.ratioY  
              _this.$ref__barY.style.transform = `translateY(${_this.$ref__wrap.scrollTop / _this.ratioY}px)`  
              c.clientY = evt.clientY  
            }  
            if(c.dragX) {  
              _this.$ref__wrap.scrollLeft += (evt.clientX - c.clientX) * _this.ratioX  
              _this.$ref__barX.style.transform = `translateX(${_this.$ref__wrap.scrollLeft / _this.ratioX}px)`  
              c.clientX = evt.clientX  
            }  
          }  
        })  
        domUtils.on(document, 'mouseup', function() {  
          _this.isTaped = false  

          document.onmouseup = null;  
          document.onselectstart = null  
        })  
      },  

      // 滚动槽  
      handleClickTrack(e, index) {  
        console.log(index)  
      },  

      // 更新滚动  
      updated() {  
        if(this.native) return  

        // 垂直滚动条  
        if(this.$ref__wrap.scrollHeight > this.$ref__wrap.offsetHeight) {  
          this.barHeight = this.$ref__box.offsetHeight **2 / this.$ref__wrap.scrollHeight  
          this.ratioY = (this.$ref__wrap.scrollHeight - this.$ref__box.offsetHeight) / (this.$ref__box.offsetHeight - this.barHeight)  
          this.$ref__barY.style.transform = `translateY(${this.$ref__wrap.scrollTop / this.ratioY}px)`  
        }else {  
          this.barHeight = 0  
          this.$ref__barY.style.transform = ''  
          this.$ref__wrap.style.marginRight = ''  
        }  

        // 水平滚动条  
        ...  
      },  

      handleResize() {  
        // 更新滚动条状态  
      },  

      // ...  
    }  
  }  
</script>

vue中directives指令函数监听DOM变化。

// 监听元素/DOM尺寸变化  
directives: {  
    'resize': {  
        bind: function(el, binding) {  
            let width = '', height = '';  
            function get() {  
            const elStyle = el.currentStyle ? el.currentStyle : document.defaultView.getComputedStyle(el, null);  
            if (width !== elStyle.width || height !== elStyle.height) {  
                binding.value({width, height});  
            }  
            width = elStyle.width;  
            height = elStyle.height;  
            }  
            el.__vueReize__ = setInterval(get, 16);  
        },  
        unbind: function(el) {  
            clearInterval(el.__vueReize__);  
        }  
    }  
}

img

img

好了,今天就分享到这里。希望大家能喜欢哈!

基于vue.js网页弹窗组件|vue自定义对话框VLayer

img

链接:https://juejin.cn/post/6901103494971785223/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

收起阅读 »

uni-app 广告心得

每天开屏展示pv 500 , 点击 50 。收益0.1-0.4. 大家自己体会分析

每天开屏展示pv 500 , 点击 50 。收益0.1-0.4. 大家自己体会分析

做外包做私活的同学们来吧

支付宝小程序 微信小程序 小程序

小程序开发交流群

群号:374213882

小程序开发交流群

群号:374213882

曝光个小人!发个接外包的贴被同行诬蔑 加他微信问为什么被瞬间拉黑

招聘 uni_app 外包 uniapp

他回帖道歉说认错人了,那就算了吧!

他回帖道歉说认错人了,那就算了吧!