HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uni-app中如何使用5+的原生界面控件(包括map、video、livepusher、barcode、nview)

原生控件 nview

uni-app可以调用plus的api操作扩展能力,这块很简单,在app的条件编译里直接写就好了,也不需要plus ready。
但是HTML5 里有很多原生的可视化控件,包括map、video、livepusher、barcode、nview(包括原生头、原生tab),获取这些对象和操作他们需要有特殊写法。
5+app开发时,我们可以用plus.webview.currentWebview获取当前页面,但uni-app里用法不一样,需要这样取当前显示的webview:

const currentWebview = this.$mp.page.$getAppWebview(); //注意相关操作写在APP-PLUS条件编译下

还有一种写法比较冗余,可以获取页面栈中任意一个webview对象:

var pages = getCurrentPages();  
var page = pages[pages.length - 1];  
// #ifdef APP-PLUS  
var currentWebview = page.$getAppWebview(); //页面栈最顶层就是当前webview  
// #endif

注意uni-app不需要像5+App那样等待plus ready,可以直接用。
有了这个currentWebview ,我们就可以做很多事情了,比如:

例子1 创建直播推流

虽然uni-app的nvue页面已经提供了直播组件。但uni-app的vue页面还没有封装,在app里的vue页面使用直播推流就得用这种写法了。(这里指的是推流,如果是拉流,在app侧可直接使用video标签)

var pusher = plus.video.createLivePusher("", {  
    url:'rtmp://testlivesdk.v0.upaiyun.com/live/upyunb',  
    top:'100px',  
    left:'0px',  
    width: '100%',  
    height: '300px',  
    position: 'static'  
});  
currentWebview.append(pusher);

在之前的5+app里,可以使用占位div来布局位置,但在uni-app里,因为没有dom,也没有占位id,所以通过js自己设置原生控件的大小和位置。

例子2 自定义扫码

uni-app的扫码api自带的扫码界面无法有效自定义,大家可以在一个自己的页面里放置一块区域显示扫码控件。

var barcode = plus.barcode.create('barcode', [plus.barcode.QR], {  
    top:'100px',  
    left:'0px',  
    width: '300px',  
    height: '300px',  
    position: 'static'  
});  
//此处未演示扫码成功回调的地址设置,实际请参考HTML5Plus API自行处理  
//注意扫码区域需为正方形,否则影响扫码识别率  
currentWebview.append(barcode);

当然如果使用app-nvue的话,有自带的barcode组件。

例子3 自定义地图

uni-app的原则是vue语法+小程序api。但小程序的api不如plus.map丰富,地图的重度开发者仍然需要plus的map。
uni-app中单独优化了这个地图的获取,通过$getAppMap可直接得到map对象。
然后参考plus.map的api实现更多地图功能。

例子4 给tabbar加个凸起

本例子仅适用于非自定义组件模式
注意tabbar的获取,不是走getCurrentPages,而是用plus.webview.currentWebview()

var centerButtonOnTab = new plus.nativeObj.View("",{top:'500px',left:'160px',height:'50px',width:'50px',backgroundColor:'#FF0000'});  
plus.webview.currentWebview().append(centerButtonOnTab);

这里只是基础演示,大小位置、点击事件,在实际开发中都得自己处理。
插件市场有已经做好的例子:https://ext.dcloud.net.cn/plugin?id=251

如果app端想要高性能的tabbar凸起,建议使用nvue在前端自绘tabbar。

例子5 操作titleNView,给titleNView右上角加个红点

var nTitle = currentWebview.getTitleNView();  
nTitle.drawBitmap("static/reddot.png",{}, {top:'3px',left:'340px',width:'4px',height:'4px'}); //具体尺寸在商用时需自行计算。红点图在附件里。  
//nview的api非常多,具体参考:http://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View

清除刚才绘制的红点

nTitle.reset();

更新:1.5版的HBuilderX已经支持titleNView的button直接设红点了,hello uni-app的模板里运行到app时也能看到相应示例源码。所以本例子实际作用已经过期,此处纯粹演示用。

5+的plus.nativeObj.view,本质是一种类canvas的画布,可以自由的draw内容上去,更新管理也需要自己维护操作。
包括想在原生控件比如视频、地图上加点什么东西,因为HTML的组件是盖不住原生组件的,都可以使用nview来做。

例子6 uni-app可以在vue页面里写web-view组件,这个组件如何用plus api操作?

vue页面里的web-view 组件其实是一个子webview。
在vue里,通过本文开头的代码,先得到当前页面的webview。
然后调用currentWebview.children()方法来获得所有子webview。
因为执行代码的时机不同,可能执行太早会返回空结果。
如果确定页面里有web-view,则可以再延时一下然后再获取一次children。
这样就能拿到这个子webview。
有了子webview对象后,可以用5+丰富的api来进行前进、后退、拦截资源、禁用schema跳转、注入js等各种操作。具体参考https://www.html5plus.org/doc/zh_cn/webview.html

具体请参考web-view组件的文档

继续阅读 »

uni-app可以调用plus的api操作扩展能力,这块很简单,在app的条件编译里直接写就好了,也不需要plus ready。
但是HTML5 里有很多原生的可视化控件,包括map、video、livepusher、barcode、nview(包括原生头、原生tab),获取这些对象和操作他们需要有特殊写法。
5+app开发时,我们可以用plus.webview.currentWebview获取当前页面,但uni-app里用法不一样,需要这样取当前显示的webview:

const currentWebview = this.$mp.page.$getAppWebview(); //注意相关操作写在APP-PLUS条件编译下

还有一种写法比较冗余,可以获取页面栈中任意一个webview对象:

var pages = getCurrentPages();  
var page = pages[pages.length - 1];  
// #ifdef APP-PLUS  
var currentWebview = page.$getAppWebview(); //页面栈最顶层就是当前webview  
// #endif

注意uni-app不需要像5+App那样等待plus ready,可以直接用。
有了这个currentWebview ,我们就可以做很多事情了,比如:

例子1 创建直播推流

虽然uni-app的nvue页面已经提供了直播组件。但uni-app的vue页面还没有封装,在app里的vue页面使用直播推流就得用这种写法了。(这里指的是推流,如果是拉流,在app侧可直接使用video标签)

var pusher = plus.video.createLivePusher("", {  
    url:'rtmp://testlivesdk.v0.upaiyun.com/live/upyunb',  
    top:'100px',  
    left:'0px',  
    width: '100%',  
    height: '300px',  
    position: 'static'  
});  
currentWebview.append(pusher);

在之前的5+app里,可以使用占位div来布局位置,但在uni-app里,因为没有dom,也没有占位id,所以通过js自己设置原生控件的大小和位置。

例子2 自定义扫码

uni-app的扫码api自带的扫码界面无法有效自定义,大家可以在一个自己的页面里放置一块区域显示扫码控件。

var barcode = plus.barcode.create('barcode', [plus.barcode.QR], {  
    top:'100px',  
    left:'0px',  
    width: '300px',  
    height: '300px',  
    position: 'static'  
});  
//此处未演示扫码成功回调的地址设置,实际请参考HTML5Plus API自行处理  
//注意扫码区域需为正方形,否则影响扫码识别率  
currentWebview.append(barcode);

当然如果使用app-nvue的话,有自带的barcode组件。

例子3 自定义地图

uni-app的原则是vue语法+小程序api。但小程序的api不如plus.map丰富,地图的重度开发者仍然需要plus的map。
uni-app中单独优化了这个地图的获取,通过$getAppMap可直接得到map对象。
然后参考plus.map的api实现更多地图功能。

例子4 给tabbar加个凸起

本例子仅适用于非自定义组件模式
注意tabbar的获取,不是走getCurrentPages,而是用plus.webview.currentWebview()

var centerButtonOnTab = new plus.nativeObj.View("",{top:'500px',left:'160px',height:'50px',width:'50px',backgroundColor:'#FF0000'});  
plus.webview.currentWebview().append(centerButtonOnTab);

这里只是基础演示,大小位置、点击事件,在实际开发中都得自己处理。
插件市场有已经做好的例子:https://ext.dcloud.net.cn/plugin?id=251

如果app端想要高性能的tabbar凸起,建议使用nvue在前端自绘tabbar。

例子5 操作titleNView,给titleNView右上角加个红点

var nTitle = currentWebview.getTitleNView();  
nTitle.drawBitmap("static/reddot.png",{}, {top:'3px',left:'340px',width:'4px',height:'4px'}); //具体尺寸在商用时需自行计算。红点图在附件里。  
//nview的api非常多,具体参考:http://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View

清除刚才绘制的红点

nTitle.reset();

更新:1.5版的HBuilderX已经支持titleNView的button直接设红点了,hello uni-app的模板里运行到app时也能看到相应示例源码。所以本例子实际作用已经过期,此处纯粹演示用。

5+的plus.nativeObj.view,本质是一种类canvas的画布,可以自由的draw内容上去,更新管理也需要自己维护操作。
包括想在原生控件比如视频、地图上加点什么东西,因为HTML的组件是盖不住原生组件的,都可以使用nview来做。

例子6 uni-app可以在vue页面里写web-view组件,这个组件如何用plus api操作?

vue页面里的web-view 组件其实是一个子webview。
在vue里,通过本文开头的代码,先得到当前页面的webview。
然后调用currentWebview.children()方法来获得所有子webview。
因为执行代码的时机不同,可能执行太早会返回空结果。
如果确定页面里有web-view,则可以再延时一下然后再获取一次children。
这样就能拿到这个子webview。
有了子webview对象后,可以用5+丰富的api来进行前进、后退、拦截资源、禁用schema跳转、注入js等各种操作。具体参考https://www.html5plus.org/doc/zh_cn/webview.html

具体请参考web-view组件的文档

收起阅读 »

获取webView.getSettings()

获取webView.getSettings():

var Webview = plus.android.importClass("android.webkit.WebView");  
var WebSettings = plus.android.importClass("android.webkit.WebSettings");  
var wv = plus.android.currentWebview();  
var setting = plus.android.invoke(wv, "getSettings");

详见博客:native.js设置可缩放的webview并隐藏缩放控件

继续阅读 »

获取webView.getSettings():

var Webview = plus.android.importClass("android.webkit.WebView");  
var WebSettings = plus.android.importClass("android.webkit.WebSettings");  
var wv = plus.android.currentWebview();  
var setting = plus.android.invoke(wv, "getSettings");

详见博客:native.js设置可缩放的webview并隐藏缩放控件

收起阅读 »

android软件开发之仿淘宝选择规格的实现

  在一些app开发项目中选择商品规格这个功能最容易遇到问题,想要实现需要的全部功能,但一直没有成功,所以就去找了个Demo,学习界面UI采用recyclerview,item里面渲染ViewGroup,根据数据源的数量,往ViewGroup里面添加Textview。这样就可以解决它的每个属性按钮宽高自适应。下面来详细分享一下源码:
/**

  • 测量子view大小 根据子控件设置宽和高

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

{

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 获得它的父容器为它设置的测量模式和大小

int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);

int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

int modeWidth = MeasureSpec.getMode(widthMeasureSpec);

int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

// 如果是warp_content情况下,记录宽和高

int width = 0;

int height = 0;

/**

  • 记录每一行的宽度,width不断取最大宽度

*/

int lineWidth = 0;

/**

  • 每一行的高度,累加至height

*/

int lineHeight = 0;

int cCount = getChildCount();

// 遍历每个子元素

for (int i = 0; i < cCount; i++)

{

View child = getChildAt(i);

// 测量每一个child的宽和高

measureChild(child, widthMeasureSpec, heightMeasureSpec);

// 得到child的布局管理器

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

// 当前子空间实际占据的宽度

int childWidth = child.getMeasuredWidth() + lp.leftMargin

  • lp.rightMargin;

// 当前子空间实际占据的高度

int childHeight = child.getMeasuredHeight() + lp.topMargin

  • lp.bottomMargin;

/**

  • 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,类加height 然后开启新行

*/

if (lineWidth + childWidth > sizeWidth)

{

width = Math.max(lineWidth, childWidth);// 取最大的

lineWidth = childWidth; // 重新开启新行,开始记录

// 叠加当前高度,

height += lineHeight;

// 开启记录下一行的高度

lineHeight = childHeight;

} else

// 否则累加值lineWidth,lineHeight取最大高度

{

lineWidth += childWidth;

lineHeight = Math.max(lineHeight, childHeight);

}

// 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较

if (i == cCount - 1)

{

width = Math.max(width, lineWidth);

height += lineHeight;

}

}

setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ?sizeWidth

width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight

height);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b)

{

mAllViews.clear();

mLineHeight.clear();

int width = getWidth();

int lineWidth = 0;

int lineHeight = 0;

// 存储每一行所有的childView

ListlineViews = new ArrayList<>();

int cCount = getChildCount();

// 遍历所有的孩子

for (int i = 0; i < cCount; i++)

{

View child = getChildAt(i);

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

int childWidth = child.getMeasuredWidth();

int childHeight = child.getMeasuredHeight();

// 如果已经需要换行

if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width)

{

// 记录这一行所有的View以及最大高度

mLineHeight.add(lineHeight);

// 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView

mAllViews.add(lineViews);

lineWidth = 0;// 重置行宽

lineViews = new ArrayList<>();

}

/**

  • 如果不需要换行,则累加

*/

lineWidth += childWidth + lp.leftMargin + lp.rightMargin;

lineHeight = Math.max(lineHeight, childHeight + lp.topMargin

  • lp.bottomMargin);

lineViews.add(child);

}

// 记录最后一行

mLineHeight.add(lineHeight);

mAllViews.add(lineViews);

int left = 0;

int top = 0;

// 得到总行数

int lineNums = mAllViews.size();

for (int i = 0; i < lineNums; i++)

{

// 每一行的所有的views

lineViews = mAllViews.get(i);

// 当前行的最大高度

lineHeight = mLineHeight.get(i);

// 遍历当前行所有的View

for (int j = 0; j < lineViews.size(); j++)

{

View child = lineViews.get(j);

if (child.getVisibility() == View.GONE)

{

continue;

}

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

//计算childView的Marginleft,top,right,bottom

int lc = left + lp.leftMargin;

int tc = top + lp.topMargin;

int rc =lc + child.getMeasuredWidth();

int bc = tc + child.getMeasuredHeight();

child.layout(lc, tc, rc, bc);

left += child.getMeasuredWidth() + lp.rightMargin

  • lp.leftMargin;

}

left = 0;

top += lineHeight;

}

}

接下来是SKU的算法,把选项状态(三种:不能选择,可以选择,已选中)依次对属性按钮做出修改,这里虽然做了一些不必要的循环判断,但胜在功能的实现adapter代码(重点initOptions、canClickOptions和getSelected三个方法)

public class GoodsAttrsAdapter extends BaseRecyclerAdapter {

private SKUInterface myInterface;

private SimpleArrayMap saveClick;

private List stockGoodsList;//商品数据集合

private String[] selectedValue; //选中的属性

private TextView[][] childrenViews; //二维 装所有属性

private final int SELECTED = 0x100;

private final int CANCEL = 0x101;

public GoodsAttrsAdapter(Context ctx, List list, List stockGoodsList) {

super(ctx, list);

this.stockGoodsList = stockGoodsList;

saveClick = new SimpleArrayMap<>();

childrenViews = new TextView[list.size()][0];

selectedValue = new String[list.size()];

for (int i = 0; i < list.size(); i++) {

selectedValue[i] = "";

}

}

public void setSKUInterface(SKUInterface myInterface) {

this.myInterface = myInterface;

}

@Override

public int getItemLayoutId(int viewType) {

return R.layout.item_skuattrs;

}

@Override

public void bindData(RecyclerViewHolder holder, int position, GoodsAttrsBean.AttributesBean item) {

TextView tv_ItemName = holder.getTextView(R.id.tv_ItemName);

SKUViewGroup vg_skuItem = (SKUViewGroup) holder.getView(R.id.vg_skuItem);

tv_ItemName.setText(item.getTabName());

Listchildrens = item.getAttributesItem();

int childrenSize = childrens.size();

TextView[] textViews = new TextView[childrenSize];

for (int i = 0; i < childrenSize; i++) {

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

params.setMargins(5, 5, 5, 0);

TextView textView = new TextView(mContext);

textView.setGravity(Gravity.CENTER);

textView.setPadding(15, 5, 15, 5);

textView.setLayoutParams(params);

textView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));

textView.setText(childrens.get(i));

textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));

textViews[i] = textView;

vg_skuItem.addView(textViews[i]);

}

childrenViews[position] = textViews;

initOptions();

canClickOptions();

getSelected();

}

private int focusPositionG, focusPositionC;

private class MyOnClickListener implements View.OnClickListener {

//点击操作 选中SELECTED 取消CANCEL

private int operation;

private int positionG;

private int positionC;

public MyOnClickListener(int operation, int positionG, int positionC) {

this.operation = operation;

this.positionG = positionG;

this.positionC = positionC;

}

@Override

public void onClick(View v) {

focusPositionG = positionG;

focusPositionC = positionC;

String value = childrenViews[positionG][positionC].getText().toString();

switch (operation) {

case SELECTED:

saveClick.put(positionG, positionC + "");

selectedValue[positionG] = value;

myInterface.selectedAttribute(selectedValue);

break;

case CANCEL:

saveClick.put(positionG, "");

for (int l = 0; l < selectedValue.length; l++) {

if (selectedValue[l].equals(value)) {

selectedValue[l] = "";

break;

}

}

myInterface.uncheckAttribute(selectedValue);

break;

}

initOptions();

canClickOptions();

getSelected();

}

}

class MyOnFocusChangeListener implements View.OnFocusChangeListener {

private int positionG;

private int positionC;

public MyOnFocusChangeListener(int positionG, int positionC) {

this.positionG = positionG;

this.positionC = positionC;

}

@Override

public void onFocusChange(View v, boolean hasFocus) {

String clickpositionC = saveClick.get(positionG);

if (hasFocus) {

v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.pink));

if (TextUtils.isEmpty(clickpositionC)) {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

} else if (clickpositionC.equals(positionC + "")) {

} else {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

}

} else {

v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));

if (TextUtils.isEmpty(clickpositionC)) {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));

} else if (clickpositionC.equals(positionC + "")) {

} else {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));

}

}

}

}

/**

  • 初始化选项(不可点击,焦点消失)

*/

private void initOptions() {

for (int y = 0; y < childrenViews.length; y++) {

for (int z = 0; z < childrenViews[y].length; z++) {//循环所有属性

TextView textView = childrenViews[y][z];

textView.setEnabled(false);

textView.setFocusable(false);

textView.setTextColor(ContextCompat.getColor(mContext, R.color.gray));//变灰

}

}

}

/**

  • 找到符合条件的选项变为可选

*/

private void canClickOptions() {

for (int i = 0; i < childrenViews.length; i++) {

for (int j = 0; j < stockGoodsList.size(); j++) {

boolean filter = false;

List goodsInfo = stockGoodsList.get(j).getGoodsInfo();

for (int k = 0; k < selectedValue.length; k++) {

if (i == k || TextUtils.isEmpty(selectedValue[k])) {

continue;

}

if (!selectedValue[k].equals(goodsInfo

.get(k).getTabValue())) {

filter = true;

break;

}

}

if (!filter) {

for (int n = 0; n < childrenViews[i].length; n++) {

TextView textView = childrenViews[i][n];//拿到所有属性TextView

String name = textView.getText().toString();

//拿到属性名称

if (goodsInfo.get(i).getTabValue().equals(name)) {

textView.setEnabled(true);//符合就变成可点击

textView.setFocusable(true); //设置可以获取焦点

//不要让焦点乱跑

if (focusPositionG == i && focusPositionC == n) {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

textView.requestFocus();

} else {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));

}

textView.setOnClickListener(new MyOnClickListener(SELECTED, i, n) {

});

textView.setOnFocusChangeListener(new MyOnFocusChangeListener(i, n) {

});

}

}

}

}

}

}

/**

  • 找到已经选中的选项,让其变红

*/

private void getSelected() {

for (int i = 0; i < childrenViews.length; i++) {

for (int j = 0; j < childrenViews[i].length; j++) {//拿到每行属性Item

TextView textView = childrenViews[i][j];//拿到所有属性TextView

String value = textView.getText().toString();

for (int m = 0; m < selectedValue.length; m++) {

if (selectedValue[m].equals(value)) {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.red));

textView.setOnClickListener(new MyOnClickListener(CANCEL, i, j) {

});

}

}

}

}

}

}

  好了,到这里就算是结束了,如果还是存在有疑问的地方,大家可以留言咨询。
  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

继续阅读 »

  在一些app开发项目中选择商品规格这个功能最容易遇到问题,想要实现需要的全部功能,但一直没有成功,所以就去找了个Demo,学习界面UI采用recyclerview,item里面渲染ViewGroup,根据数据源的数量,往ViewGroup里面添加Textview。这样就可以解决它的每个属性按钮宽高自适应。下面来详细分享一下源码:
/**

  • 测量子view大小 根据子控件设置宽和高

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

{

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 获得它的父容器为它设置的测量模式和大小

int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);

int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

int modeWidth = MeasureSpec.getMode(widthMeasureSpec);

int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

// 如果是warp_content情况下,记录宽和高

int width = 0;

int height = 0;

/**

  • 记录每一行的宽度,width不断取最大宽度

*/

int lineWidth = 0;

/**

  • 每一行的高度,累加至height

*/

int lineHeight = 0;

int cCount = getChildCount();

// 遍历每个子元素

for (int i = 0; i < cCount; i++)

{

View child = getChildAt(i);

// 测量每一个child的宽和高

measureChild(child, widthMeasureSpec, heightMeasureSpec);

// 得到child的布局管理器

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

// 当前子空间实际占据的宽度

int childWidth = child.getMeasuredWidth() + lp.leftMargin

  • lp.rightMargin;

// 当前子空间实际占据的高度

int childHeight = child.getMeasuredHeight() + lp.topMargin

  • lp.bottomMargin;

/**

  • 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,类加height 然后开启新行

*/

if (lineWidth + childWidth > sizeWidth)

{

width = Math.max(lineWidth, childWidth);// 取最大的

lineWidth = childWidth; // 重新开启新行,开始记录

// 叠加当前高度,

height += lineHeight;

// 开启记录下一行的高度

lineHeight = childHeight;

} else

// 否则累加值lineWidth,lineHeight取最大高度

{

lineWidth += childWidth;

lineHeight = Math.max(lineHeight, childHeight);

}

// 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较

if (i == cCount - 1)

{

width = Math.max(width, lineWidth);

height += lineHeight;

}

}

setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ?sizeWidth

width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight

height);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b)

{

mAllViews.clear();

mLineHeight.clear();

int width = getWidth();

int lineWidth = 0;

int lineHeight = 0;

// 存储每一行所有的childView

ListlineViews = new ArrayList<>();

int cCount = getChildCount();

// 遍历所有的孩子

for (int i = 0; i < cCount; i++)

{

View child = getChildAt(i);

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

int childWidth = child.getMeasuredWidth();

int childHeight = child.getMeasuredHeight();

// 如果已经需要换行

if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width)

{

// 记录这一行所有的View以及最大高度

mLineHeight.add(lineHeight);

// 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView

mAllViews.add(lineViews);

lineWidth = 0;// 重置行宽

lineViews = new ArrayList<>();

}

/**

  • 如果不需要换行,则累加

*/

lineWidth += childWidth + lp.leftMargin + lp.rightMargin;

lineHeight = Math.max(lineHeight, childHeight + lp.topMargin

  • lp.bottomMargin);

lineViews.add(child);

}

// 记录最后一行

mLineHeight.add(lineHeight);

mAllViews.add(lineViews);

int left = 0;

int top = 0;

// 得到总行数

int lineNums = mAllViews.size();

for (int i = 0; i < lineNums; i++)

{

// 每一行的所有的views

lineViews = mAllViews.get(i);

// 当前行的最大高度

lineHeight = mLineHeight.get(i);

// 遍历当前行所有的View

for (int j = 0; j < lineViews.size(); j++)

{

View child = lineViews.get(j);

if (child.getVisibility() == View.GONE)

{

continue;

}

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

//计算childView的Marginleft,top,right,bottom

int lc = left + lp.leftMargin;

int tc = top + lp.topMargin;

int rc =lc + child.getMeasuredWidth();

int bc = tc + child.getMeasuredHeight();

child.layout(lc, tc, rc, bc);

left += child.getMeasuredWidth() + lp.rightMargin

  • lp.leftMargin;

}

left = 0;

top += lineHeight;

}

}

接下来是SKU的算法,把选项状态(三种:不能选择,可以选择,已选中)依次对属性按钮做出修改,这里虽然做了一些不必要的循环判断,但胜在功能的实现adapter代码(重点initOptions、canClickOptions和getSelected三个方法)

public class GoodsAttrsAdapter extends BaseRecyclerAdapter {

private SKUInterface myInterface;

private SimpleArrayMap saveClick;

private List stockGoodsList;//商品数据集合

private String[] selectedValue; //选中的属性

private TextView[][] childrenViews; //二维 装所有属性

private final int SELECTED = 0x100;

private final int CANCEL = 0x101;

public GoodsAttrsAdapter(Context ctx, List list, List stockGoodsList) {

super(ctx, list);

this.stockGoodsList = stockGoodsList;

saveClick = new SimpleArrayMap<>();

childrenViews = new TextView[list.size()][0];

selectedValue = new String[list.size()];

for (int i = 0; i < list.size(); i++) {

selectedValue[i] = "";

}

}

public void setSKUInterface(SKUInterface myInterface) {

this.myInterface = myInterface;

}

@Override

public int getItemLayoutId(int viewType) {

return R.layout.item_skuattrs;

}

@Override

public void bindData(RecyclerViewHolder holder, int position, GoodsAttrsBean.AttributesBean item) {

TextView tv_ItemName = holder.getTextView(R.id.tv_ItemName);

SKUViewGroup vg_skuItem = (SKUViewGroup) holder.getView(R.id.vg_skuItem);

tv_ItemName.setText(item.getTabName());

Listchildrens = item.getAttributesItem();

int childrenSize = childrens.size();

TextView[] textViews = new TextView[childrenSize];

for (int i = 0; i < childrenSize; i++) {

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

params.setMargins(5, 5, 5, 0);

TextView textView = new TextView(mContext);

textView.setGravity(Gravity.CENTER);

textView.setPadding(15, 5, 15, 5);

textView.setLayoutParams(params);

textView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));

textView.setText(childrens.get(i));

textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));

textViews[i] = textView;

vg_skuItem.addView(textViews[i]);

}

childrenViews[position] = textViews;

initOptions();

canClickOptions();

getSelected();

}

private int focusPositionG, focusPositionC;

private class MyOnClickListener implements View.OnClickListener {

//点击操作 选中SELECTED 取消CANCEL

private int operation;

private int positionG;

private int positionC;

public MyOnClickListener(int operation, int positionG, int positionC) {

this.operation = operation;

this.positionG = positionG;

this.positionC = positionC;

}

@Override

public void onClick(View v) {

focusPositionG = positionG;

focusPositionC = positionC;

String value = childrenViews[positionG][positionC].getText().toString();

switch (operation) {

case SELECTED:

saveClick.put(positionG, positionC + "");

selectedValue[positionG] = value;

myInterface.selectedAttribute(selectedValue);

break;

case CANCEL:

saveClick.put(positionG, "");

for (int l = 0; l < selectedValue.length; l++) {

if (selectedValue[l].equals(value)) {

selectedValue[l] = "";

break;

}

}

myInterface.uncheckAttribute(selectedValue);

break;

}

initOptions();

canClickOptions();

getSelected();

}

}

class MyOnFocusChangeListener implements View.OnFocusChangeListener {

private int positionG;

private int positionC;

public MyOnFocusChangeListener(int positionG, int positionC) {

this.positionG = positionG;

this.positionC = positionC;

}

@Override

public void onFocusChange(View v, boolean hasFocus) {

String clickpositionC = saveClick.get(positionG);

if (hasFocus) {

v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.pink));

if (TextUtils.isEmpty(clickpositionC)) {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

} else if (clickpositionC.equals(positionC + "")) {

} else {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

}

} else {

v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));

if (TextUtils.isEmpty(clickpositionC)) {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));

} else if (clickpositionC.equals(positionC + "")) {

} else {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));

}

}

}

}

/**

  • 初始化选项(不可点击,焦点消失)

*/

private void initOptions() {

for (int y = 0; y < childrenViews.length; y++) {

for (int z = 0; z < childrenViews[y].length; z++) {//循环所有属性

TextView textView = childrenViews[y][z];

textView.setEnabled(false);

textView.setFocusable(false);

textView.setTextColor(ContextCompat.getColor(mContext, R.color.gray));//变灰

}

}

}

/**

  • 找到符合条件的选项变为可选

*/

private void canClickOptions() {

for (int i = 0; i < childrenViews.length; i++) {

for (int j = 0; j < stockGoodsList.size(); j++) {

boolean filter = false;

List goodsInfo = stockGoodsList.get(j).getGoodsInfo();

for (int k = 0; k < selectedValue.length; k++) {

if (i == k || TextUtils.isEmpty(selectedValue[k])) {

continue;

}

if (!selectedValue[k].equals(goodsInfo

.get(k).getTabValue())) {

filter = true;

break;

}

}

if (!filter) {

for (int n = 0; n < childrenViews[i].length; n++) {

TextView textView = childrenViews[i][n];//拿到所有属性TextView

String name = textView.getText().toString();

//拿到属性名称

if (goodsInfo.get(i).getTabValue().equals(name)) {

textView.setEnabled(true);//符合就变成可点击

textView.setFocusable(true); //设置可以获取焦点

//不要让焦点乱跑

if (focusPositionG == i && focusPositionC == n) {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

textView.requestFocus();

} else {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));

}

textView.setOnClickListener(new MyOnClickListener(SELECTED, i, n) {

});

textView.setOnFocusChangeListener(new MyOnFocusChangeListener(i, n) {

});

}

}

}

}

}

}

/**

  • 找到已经选中的选项,让其变红

*/

private void getSelected() {

for (int i = 0; i < childrenViews.length; i++) {

for (int j = 0; j < childrenViews[i].length; j++) {//拿到每行属性Item

TextView textView = childrenViews[i][j];//拿到所有属性TextView

String value = textView.getText().toString();

for (int m = 0; m < selectedValue.length; m++) {

if (selectedValue[m].equals(value)) {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.red));

textView.setOnClickListener(new MyOnClickListener(CANCEL, i, j) {

});

}

}

}

}

}

}

  好了,到这里就算是结束了,如果还是存在有疑问的地方,大家可以留言咨询。
  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

收起阅读 »

设置headers 报错Request header field Content-Type is not allowed by Access-Control-Allow-Headers

headers

我要自定义一些参数放在headers里面,试了好多方法都不行
比如:http://ask.dcloud.net.cn/question/8596这里的很多个方式
http://ask.dcloud.net.cn/article/13026的方式
后来比较明确的报错Request header field “我自定义的key” is not allowed by Access-Control-Allow-Headers in preflight response.
又去搜了一下找到https://www.cnblogs.com/caimuqing/p/6733405.html,结果发现是后端需要把要传到后端的headers里面的key加入到response

// TODO 支持跨域访问  
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Credentials", "true");  
        response.setHeader("Access-Control-Allow-Methods", "*");  
        response.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");//这里“Access-Token”是我要传到后台的内容key  
        response.setHeader("Access-Control-Expose-Headers", "*");  

        if (request.getMethod().equals("OPTIONS")) {  
            HttpUtil.setResponse(response, HttpStatus.OK.value(), null);  
            return;  
        }

共勉给想要自定义headers的同学

继续阅读 »

我要自定义一些参数放在headers里面,试了好多方法都不行
比如:http://ask.dcloud.net.cn/question/8596这里的很多个方式
http://ask.dcloud.net.cn/article/13026的方式
后来比较明确的报错Request header field “我自定义的key” is not allowed by Access-Control-Allow-Headers in preflight response.
又去搜了一下找到https://www.cnblogs.com/caimuqing/p/6733405.html,结果发现是后端需要把要传到后端的headers里面的key加入到response

// TODO 支持跨域访问  
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Credentials", "true");  
        response.setHeader("Access-Control-Allow-Methods", "*");  
        response.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");//这里“Access-Token”是我要传到后台的内容key  
        response.setHeader("Access-Control-Expose-Headers", "*");  

        if (request.getMethod().equals("OPTIONS")) {  
            HttpUtil.setResponse(response, HttpStatus.OK.value(), null);  
            return;  
        }

共勉给想要自定义headers的同学

收起阅读 »

微信公众号开发之客服功能的群发消息功能

  本周我们做了一个有技术含量的一个新功能:客服功能的群发消息功能。此功能主要用于微信公众号客服群发提醒,比如客户的商家认证审核通过,用户购买商品成功等功能提醒,可以有效减少网站项目开发所必要的资金节约。

  1. 接口代码。

接口代码如下:

public function reply_customer(){

$mtime=strtotime("-1 hour");

$where['add_time']=array("gt",$mtime);

$res=M("fa_need")->where($where)->order("id desc")->find();

$id=$res['id'];

$new_time=time();

$go_time=$res['add_time']+$res['show_time']*60;

if($new_time<$go_time){

$credit_level=$res['credit_level'];

$ya_money=$res['ya_money'];

$wh['credit_level']=array("egt",$credit_level);

$wh['ya_money']=array("egt",$ya_money);

$wh['ya_money']=array("neq",$ya_money);

$wh['jie_status']=3;

$list=M("user")->where($wh)->limit(199)->select();

foreach ($list as $key => $value) {

$info[]=$value['openid'];

}

$touser=I('touser');

$content="亲,有新任务哦,可以点击链接接单啦!";

//更换成自己的APPID和APPSECRET

$APPID="wx4ae938a141e9193a";

$APPSECRET="d0ef15664f42de92875f86b8f9f98edf";

$TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$APPID."&secret=".$APPSECRET;

$json=file_get_contents($TOKEN_URL);

$result=json_decode($json);

$ACC_TOKEN=$result->access_token;

foreach($info as $val){

$data = '{

"touser":"'.$val.'",

"msgtype":"text",

"text":

{

"content":"'.$content.'http://www.xxx.com/Task/task_details?id='.$id.'"

}

}';

$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$ACC_TOKEN;

$result = $this->https_post($url,$data);

$final = json_decode($result);

echo $final;

}

}

}

public function https_post($url,$data)

{

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

curl_setopt($curl, CURLOPT_POST, 1);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$result = curl_exec($curl);

if (curl_errno($curl)) {

return 'Errno'.curl_error($curl);

}

curl_close($curl);

return $result;

}

  1. php调用接口代码

Php代码如下:

public function fa_need(){

vendor('Weixinup.jssdk');

$jssdk = new JSSDK("wx4ae938a141e9193a", "d0ef15664f42de92875f86b8f9f98edf");

$signPackage = $jssdk->GetSignPackage();

// var_dump($signPackage);die;

$this->assign('signPackage', $signPackage);

$uid=session('uid');

$model=M('user');

$list=$model->where("uid=$uid")->find();

$mod=M("school");

$school=$mod->select();

$this->reply_customer();

// if (I('id')!=""||!empty(I('id'))) {

// $faid["id"] = I('id');

// $res = M("fa_need")->where($faid)->find();

// $this->assign("fa_needinfo",$res);

// }

$this->assign("school",$school);

$this->assign("list",$list);

$this->display();

}

  好了,到这里大家应该清楚是如何实现的吧,那么如果还是存在有不理解的地方,可以留言咨询获取帮助解答。
  本文由专业的郑州小程序开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

继续阅读 »

  本周我们做了一个有技术含量的一个新功能:客服功能的群发消息功能。此功能主要用于微信公众号客服群发提醒,比如客户的商家认证审核通过,用户购买商品成功等功能提醒,可以有效减少网站项目开发所必要的资金节约。

  1. 接口代码。

接口代码如下:

public function reply_customer(){

$mtime=strtotime("-1 hour");

$where['add_time']=array("gt",$mtime);

$res=M("fa_need")->where($where)->order("id desc")->find();

$id=$res['id'];

$new_time=time();

$go_time=$res['add_time']+$res['show_time']*60;

if($new_time<$go_time){

$credit_level=$res['credit_level'];

$ya_money=$res['ya_money'];

$wh['credit_level']=array("egt",$credit_level);

$wh['ya_money']=array("egt",$ya_money);

$wh['ya_money']=array("neq",$ya_money);

$wh['jie_status']=3;

$list=M("user")->where($wh)->limit(199)->select();

foreach ($list as $key => $value) {

$info[]=$value['openid'];

}

$touser=I('touser');

$content="亲,有新任务哦,可以点击链接接单啦!";

//更换成自己的APPID和APPSECRET

$APPID="wx4ae938a141e9193a";

$APPSECRET="d0ef15664f42de92875f86b8f9f98edf";

$TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$APPID."&secret=".$APPSECRET;

$json=file_get_contents($TOKEN_URL);

$result=json_decode($json);

$ACC_TOKEN=$result->access_token;

foreach($info as $val){

$data = '{

"touser":"'.$val.'",

"msgtype":"text",

"text":

{

"content":"'.$content.'http://www.xxx.com/Task/task_details?id='.$id.'"

}

}';

$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$ACC_TOKEN;

$result = $this->https_post($url,$data);

$final = json_decode($result);

echo $final;

}

}

}

public function https_post($url,$data)

{

$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

curl_setopt($curl, CURLOPT_POST, 1);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$result = curl_exec($curl);

if (curl_errno($curl)) {

return 'Errno'.curl_error($curl);

}

curl_close($curl);

return $result;

}

  1. php调用接口代码

Php代码如下:

public function fa_need(){

vendor('Weixinup.jssdk');

$jssdk = new JSSDK("wx4ae938a141e9193a", "d0ef15664f42de92875f86b8f9f98edf");

$signPackage = $jssdk->GetSignPackage();

// var_dump($signPackage);die;

$this->assign('signPackage', $signPackage);

$uid=session('uid');

$model=M('user');

$list=$model->where("uid=$uid")->find();

$mod=M("school");

$school=$mod->select();

$this->reply_customer();

// if (I('id')!=""||!empty(I('id'))) {

// $faid["id"] = I('id');

// $res = M("fa_need")->where($faid)->find();

// $this->assign("fa_needinfo",$res);

// }

$this->assign("school",$school);

$this->assign("list",$list);

$this->display();

}

  好了,到这里大家应该清楚是如何实现的吧,那么如果还是存在有不理解的地方,可以留言咨询获取帮助解答。
  本文由专业的郑州小程序开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

收起阅读 »

底部导航栏窗体切换

这几天一直在研究底部导航栏页面切换的问题一直都是不得要领,看了论团里的不少文章但是自己copy过来却又失败了,今天突发奇想的使用jQuery试了一下还真的可以。不过也有一些小问题出现,就是偶尔会在右边和下边会有滚动条闪一下。不说了发代码给大神看一下帮我分析分析该怎么解决
mui.plusReady(function() {
//设置默认打开首页显示的子页序号;
var Index = 0;
//把子页的路径写在数组里面
var subpages = ['html/shoping.html', 'html/chat.html', 'html/focus.html', 'html/person.html'];
var self = plus.webview.currentWebview();
for(var i = 0; i < subpages.length; i++) {
var sub = plus.webview.create(
subpages[i], //子页url
subpages[i], //子页id
{
top: '0px', //设置距离顶部的距离
bottom: '50px' //设置距离底部的距离
}
);
//如不是我们设置的默认的子页则隐藏,否则添加到窗口中
if(i != Index) {
sub.hide();
}
//将webview对象填充到窗口
self.append(sub);
}
//点击切换窗口的实现代码部分
$(".mui-tab-item").on('tap', function() {
var c = $(this).index();
plus.webview.show(subpages[c]);

            });  

        });
继续阅读 »

这几天一直在研究底部导航栏页面切换的问题一直都是不得要领,看了论团里的不少文章但是自己copy过来却又失败了,今天突发奇想的使用jQuery试了一下还真的可以。不过也有一些小问题出现,就是偶尔会在右边和下边会有滚动条闪一下。不说了发代码给大神看一下帮我分析分析该怎么解决
mui.plusReady(function() {
//设置默认打开首页显示的子页序号;
var Index = 0;
//把子页的路径写在数组里面
var subpages = ['html/shoping.html', 'html/chat.html', 'html/focus.html', 'html/person.html'];
var self = plus.webview.currentWebview();
for(var i = 0; i < subpages.length; i++) {
var sub = plus.webview.create(
subpages[i], //子页url
subpages[i], //子页id
{
top: '0px', //设置距离顶部的距离
bottom: '50px' //设置距离底部的距离
}
);
//如不是我们设置的默认的子页则隐藏,否则添加到窗口中
if(i != Index) {
sub.hide();
}
//将webview对象填充到窗口
self.append(sub);
}
//点击切换窗口的实现代码部分
$(".mui-tab-item").on('tap', function() {
var c = $(this).index();
plus.webview.show(subpages[c]);

            });  

        });
收起阅读 »

HTML编程之页面滚动div固定效果的实现

  Jquery页面滚动条向下拉到div的位置时,此div就固定在顶部,向上拉时返回原位置Div在网页打开时固定在某个位置(不一定是网页的最顶端),当滚动条向下滚动时,页面的顶部到达此div位置后,此div就固定在网页的最顶部跟随移动,当滚动条向上滚动时,页面顶部高过此div原来的固定位置,此div就定在原位置不再跟随滚动条移动(相当于返回原来的位置)。下面就来详细分享一下源码:
<head>

<script src="js/jquery-1.7.1.min.js" type="text/javascript"></script>  

<script type="text/javascript">  
        window.onload = function () {  
            var pos =  $('#div1').offset();// offset() 获得div1当前的位置,左上角坐标(x,y)  
            $(window).scroll(function () { //滚动条滚动事件  
                if ($(this).scrollTop() > pos.top ) {  
                    $('#div1').css('width', '100px').css('top', $(this).scrollTop() - pos.top);  
                } else if ($(this).scrollTop() <=  pos.top ) {  
                    $('#div1').css('width', '100x').css('top',0).css('position', 'relative');  
                }  

            })  

        };  

</script>

</head>

<html>

<div id="div1" style="width:100px">  

    我就是要跟着滚动条移动的div.  

</div>  

</html>
  好了,看到这里大家应该清楚是如何实现的吧,如果还是存在不理解的地方或者不知道哪里出错了,都是可以留言来获得帮助和解答。

  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

继续阅读 »

  Jquery页面滚动条向下拉到div的位置时,此div就固定在顶部,向上拉时返回原位置Div在网页打开时固定在某个位置(不一定是网页的最顶端),当滚动条向下滚动时,页面的顶部到达此div位置后,此div就固定在网页的最顶部跟随移动,当滚动条向上滚动时,页面顶部高过此div原来的固定位置,此div就定在原位置不再跟随滚动条移动(相当于返回原来的位置)。下面就来详细分享一下源码:
<head>

<script src="js/jquery-1.7.1.min.js" type="text/javascript"></script>  

<script type="text/javascript">  
        window.onload = function () {  
            var pos =  $('#div1').offset();// offset() 获得div1当前的位置,左上角坐标(x,y)  
            $(window).scroll(function () { //滚动条滚动事件  
                if ($(this).scrollTop() > pos.top ) {  
                    $('#div1').css('width', '100px').css('top', $(this).scrollTop() - pos.top);  
                } else if ($(this).scrollTop() <=  pos.top ) {  
                    $('#div1').css('width', '100x').css('top',0).css('position', 'relative');  
                }  

            })  

        };  

</script>

</head>

<html>

<div id="div1" style="width:100px">  

    我就是要跟着滚动条移动的div.  

</div>  

</html>
  好了,看到这里大家应该清楚是如何实现的吧,如果还是存在不理解的地方或者不知道哪里出错了,都是可以留言来获得帮助和解答。

  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

收起阅读 »

【力谱云】【app制作开发】移动订货行业解决方案

**【力谱云】【app制作开发】移动订货行业解决方案***>

==移动订货==
移动订货解决方案,为分销商和品牌商提供的高效移动端批发、订货和分销解决方案
让您的客户像网购一样便捷地订货,让您像京东一样高效地对客户进行营销

==核心功能==
***移动订货
专属订货商城
多平台下单
本地配送管理
多渠道支付
订货管理App

***营销推广
多渠道推广
多级分销
精准营销推送
批发优惠折扣

***客户维护
会员制管理
产品价格保护
客户分级
预付卡
会员积分
在线客服

***数据分析
实时成交分析
商品分析
交易分析
分销报表
渠道报表

==高效营销,提升销量==
集成抢购、满减、多级分销等营销工具,支持推送、短信等有效营销方式,高频互动,促成订单,增强粘性

==移动订货,高效便捷==
像网购一样订货,随时随地下单,打造高效便捷的订货体验

==专属商城,独享客户==
搭建企业专属的订货分销商城,独享所有客户和数据,并彰显切品牌和实力

==全程掌控,提升效率==
订货流程全程追踪,告别错单、漏单、拖单,本地配送支持抢单,极大提升效率

继续阅读 »

**【力谱云】【app制作开发】移动订货行业解决方案***>

==移动订货==
移动订货解决方案,为分销商和品牌商提供的高效移动端批发、订货和分销解决方案
让您的客户像网购一样便捷地订货,让您像京东一样高效地对客户进行营销

==核心功能==
***移动订货
专属订货商城
多平台下单
本地配送管理
多渠道支付
订货管理App

***营销推广
多渠道推广
多级分销
精准营销推送
批发优惠折扣

***客户维护
会员制管理
产品价格保护
客户分级
预付卡
会员积分
在线客服

***数据分析
实时成交分析
商品分析
交易分析
分销报表
渠道报表

==高效营销,提升销量==
集成抢购、满减、多级分销等营销工具,支持推送、短信等有效营销方式,高频互动,促成订单,增强粘性

==移动订货,高效便捷==
像网购一样订货,随时随地下单,打造高效便捷的订货体验

==专属商城,独享客户==
搭建企业专属的订货分销商城,独享所有客户和数据,并彰显切品牌和实力

==全程掌控,提升效率==
订货流程全程追踪,告别错单、漏单、拖单,本地配送支持抢单,极大提升效率

收起阅读 »

【力谱云】【app开发制作】移动零售行业解决方案

5 App开发 移动APP

==移动零售单店版==>
移动零售解决方案,为线下生鲜、小型超市等零售门店提供的新零售解决方案,打通线上线下场景,
一站式实现与消费者的互动营销运营

==核心功能==>
: :移动门店 多平台移动门店
精准门店导航定位
线上下单线下服务
支持独立配送团队
移动收银台

: :营销推广 多渠道推广
人人分销
拼团秒杀
优惠券代金券
满减满送
内容营销

: :客户维护 积分管理
会员等级
预付卡
社交运营
内容运营

: :数据分析 实时成交分析
商品分析
交易分析
销售报表
订单分析

==高效营销,提升复购==
集成拼团、抢购、代金券和多级分销等营销工具,高频互动,精准营销

==线上线下融合,提升留存==
线下客户,线上运营,通过积分、会员等级、预付卡等模式提升客户忠诚度

==精美商城,提升品牌==
搭建精美的线上商城,提升体验,加快品牌树立

继续阅读 »

==移动零售单店版==>
移动零售解决方案,为线下生鲜、小型超市等零售门店提供的新零售解决方案,打通线上线下场景,
一站式实现与消费者的互动营销运营

==核心功能==>
: :移动门店 多平台移动门店
精准门店导航定位
线上下单线下服务
支持独立配送团队
移动收银台

: :营销推广 多渠道推广
人人分销
拼团秒杀
优惠券代金券
满减满送
内容营销

: :客户维护 积分管理
会员等级
预付卡
社交运营
内容运营

: :数据分析 实时成交分析
商品分析
交易分析
销售报表
订单分析

==高效营销,提升复购==
集成拼团、抢购、代金券和多级分销等营销工具,高频互动,精准营销

==线上线下融合,提升留存==
线下客户,线上运营,通过积分、会员等级、预付卡等模式提升客户忠诚度

==精美商城,提升品牌==
搭建精美的线上商城,提升体验,加快品牌树立

收起阅读 »

分享 一个 github 上的翻墙 上谷歌 google 的方法,方便大家找资料

翻墙

身为开发者,需要找各种资料时,百度很多搜索不到,这时使用Google, 是个不错的选择,github 上有个还不错的翻墙方法分享给那些还不懂翻墙找资料的朋友们。

Chrome一键翻墙包

继续阅读 »

身为开发者,需要找各种资料时,百度很多搜索不到,这时使用Google, 是个不错的选择,github 上有个还不错的翻墙方法分享给那些还不懂翻墙找资料的朋友们。

Chrome一键翻墙包

收起阅读 »

哪家的郑州小程序定制开发公司要优秀些

微信小程序

  最近的这几年当中,郑州小程序开发公司的数量开始变得越来越多,如雨后春笋般的涌现出来了,在大多数这个城市也不例外,可以看到现在的小程序开发公司是非常多的,如果有小程序开发需求的时候,是有非常多的选择的。那么对于投资者来说如何选择才能保证选择好的呢?下面就跟大家来分析解答一下。

  一、看公司的创意如何

  现在的手机小程序数量太多了,导致同质化非常的严重,有很多小程序设计毫无新意,在大众使用当中也不能够引起一些好的效果。如果设计团队非常具有创意,那么它设计开发出来的小程序也将是非常新颖的,能够在众多的小程序当中脱颖而出,从而吸引更多的用户,这样也是非常的具有竞争力的。因此在选择的时候一定要选择哪些具有创意的小程序开发公司,以提高小程序的市场竞争力。

  二、看开发团队的质量如何

  一般来讲,一家好的开发公司都是拥有自己的一个专业的研发团队,比如塔尖网络,因为只有拥有自己的团队,高素质的工作人员,才能够保证公司所接的所有的开发项目能够非常顺利的进行,对于开发的成果来说,有专业团队的公司对开发质量也是非常有保障的。

  一、看实际案例

  虽然说过去所做的一些东西,并不就一定能够代表这一开发公司的好坏,但是如果一个公司过去都没有做过几个实际案例,或者说所做的案例很多都是非常的失败的,那么又怎么能够相信呢?反之,如果一家公司之前完成了非常多的优秀的、成功的案例,那么也会更加放心。因此,在选择小程序开发公司的时候,不妨多去了解、浏览一下这个公司以往的开发案例。

  四、看性价比如何

  一般来讲,好的公司提供的开发服务性价比是非常高的,花费较少的钱就能够获得较大的收获,提供功能齐全的服务,因此在选择的时候可以多进行对比,在众多的公司当中选择一家性价比最高的小程序开发公司。

  可以看出,要想选择到一家好的小程序开发公司,就必须要多多的注意以上的这几点,只要注意到了以上的这几点,那么就一定可以选择到一家好的微信小程序开发公司,从而能够开发出更好的手机小程序,使公司能够获得更大的竞争优势。信息由郑州小程序开发燚轩科技整理发布。

继续阅读 »

  最近的这几年当中,郑州小程序开发公司的数量开始变得越来越多,如雨后春笋般的涌现出来了,在大多数这个城市也不例外,可以看到现在的小程序开发公司是非常多的,如果有小程序开发需求的时候,是有非常多的选择的。那么对于投资者来说如何选择才能保证选择好的呢?下面就跟大家来分析解答一下。

  一、看公司的创意如何

  现在的手机小程序数量太多了,导致同质化非常的严重,有很多小程序设计毫无新意,在大众使用当中也不能够引起一些好的效果。如果设计团队非常具有创意,那么它设计开发出来的小程序也将是非常新颖的,能够在众多的小程序当中脱颖而出,从而吸引更多的用户,这样也是非常的具有竞争力的。因此在选择的时候一定要选择哪些具有创意的小程序开发公司,以提高小程序的市场竞争力。

  二、看开发团队的质量如何

  一般来讲,一家好的开发公司都是拥有自己的一个专业的研发团队,比如塔尖网络,因为只有拥有自己的团队,高素质的工作人员,才能够保证公司所接的所有的开发项目能够非常顺利的进行,对于开发的成果来说,有专业团队的公司对开发质量也是非常有保障的。

  一、看实际案例

  虽然说过去所做的一些东西,并不就一定能够代表这一开发公司的好坏,但是如果一个公司过去都没有做过几个实际案例,或者说所做的案例很多都是非常的失败的,那么又怎么能够相信呢?反之,如果一家公司之前完成了非常多的优秀的、成功的案例,那么也会更加放心。因此,在选择小程序开发公司的时候,不妨多去了解、浏览一下这个公司以往的开发案例。

  四、看性价比如何

  一般来讲,好的公司提供的开发服务性价比是非常高的,花费较少的钱就能够获得较大的收获,提供功能齐全的服务,因此在选择的时候可以多进行对比,在众多的公司当中选择一家性价比最高的小程序开发公司。

  可以看出,要想选择到一家好的小程序开发公司,就必须要多多的注意以上的这几点,只要注意到了以上的这几点,那么就一定可以选择到一家好的微信小程序开发公司,从而能够开发出更好的手机小程序,使公司能够获得更大的竞争优势。信息由郑州小程序开发燚轩科技整理发布。

收起阅读 »