HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uniapp向webview中发送消息

uniapp

uniapp向webview中发送消息

在业务开发中,使用webview嵌套了vue开发的h5页面,进行套壳打包,其一需求是,在h5中获取当前app的版本号,就涉及到了uniapp向webview传递消息的场景

uniapp 中代码

核心为获取到webview窗口,然后通过evalJS执行h5中的方法

  • setVersion方法为h5页面中定义的全局方法
<template>  
    <view class="content">  
        <!-- 开发 -->  
        <web-view @message="onMessage" :webview-styles="webviewStyles" src="http://192.168.1.158:3000"></web-view>  

    </view>  
</template>  
<script>  
export default {  
    data() {  
        return {  
            title: 'Hello',  
            webviewStyles: {  
                progress: {  
                    color: '#f0b90b'  
                }  
            },  
            wv: null,  
        };  
    },  
    onLoad() {  
        const self = this;  
        // #ifdef APP-PLUS  
        let currentWebview = this.$scope.$getAppWebview();  
        setTimeout(function() {  
            let wv = currentWebview.children()[0];  
            self.wv = wv;  
            self.setVersion();  
        }, 1000);  
        // #endif  

    },  
    methods: {  
        // 设置版本号  
        setVersion() {  
            const self = this;  
            plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {  
                self.wv.evalJS("setVersion('" + widgetInfo.version + "')");  
            });  
        },  
        // 接收消息  
        onMessage(e) {  
            const self = this;  
            console.log('我收到了网页发来的消息', e.detail.data);  
            let data = e.detail.data;  
        },  
    }  
};  
</script>  

h5 中代码

App.vue

// 设置版本号  
    window.setVersion = (id) => {  
      localStorage.setItem("version", version);  
    };

然后就可以在h5中获取使用了

注意

尽量不要uni生命周期中直接调用h5里面的方法,要等h5加载完成后,才可以调用

继续阅读 »

uniapp向webview中发送消息

在业务开发中,使用webview嵌套了vue开发的h5页面,进行套壳打包,其一需求是,在h5中获取当前app的版本号,就涉及到了uniapp向webview传递消息的场景

uniapp 中代码

核心为获取到webview窗口,然后通过evalJS执行h5中的方法

  • setVersion方法为h5页面中定义的全局方法
<template>  
    <view class="content">  
        <!-- 开发 -->  
        <web-view @message="onMessage" :webview-styles="webviewStyles" src="http://192.168.1.158:3000"></web-view>  

    </view>  
</template>  
<script>  
export default {  
    data() {  
        return {  
            title: 'Hello',  
            webviewStyles: {  
                progress: {  
                    color: '#f0b90b'  
                }  
            },  
            wv: null,  
        };  
    },  
    onLoad() {  
        const self = this;  
        // #ifdef APP-PLUS  
        let currentWebview = this.$scope.$getAppWebview();  
        setTimeout(function() {  
            let wv = currentWebview.children()[0];  
            self.wv = wv;  
            self.setVersion();  
        }, 1000);  
        // #endif  

    },  
    methods: {  
        // 设置版本号  
        setVersion() {  
            const self = this;  
            plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {  
                self.wv.evalJS("setVersion('" + widgetInfo.version + "')");  
            });  
        },  
        // 接收消息  
        onMessage(e) {  
            const self = this;  
            console.log('我收到了网页发来的消息', e.detail.data);  
            let data = e.detail.data;  
        },  
    }  
};  
</script>  

h5 中代码

App.vue

// 设置版本号  
    window.setVersion = (id) => {  
      localStorage.setItem("version", version);  
    };

然后就可以在h5中获取使用了

注意

尽量不要uni生命周期中直接调用h5里面的方法,要等h5加载完成后,才可以调用

收起阅读 »

uniapp原生插件-监听手机短信

原生插件

监听手机短信

实时监控手机收到的短信,可获取到发送者的手机号、时间、内容、卡槽等相关信息

使用方法

  • 下载本插件并存放到nativeplugins目录下

  • 在页面中引入这个插件

    // 监听短信插件  
    const kingReceiceSmsModule = uni.requireNativePlugin("king-receive-sms")  
  • 调用插件的方法

    kingReceiceSmsModule.addCustomizeNotifyMessage(result => {  
        <!-- result 为监听到的信息 -->  
        var str = JSON.stringify(result);  
        console.log(str)  
    });  

    信息格式

    {  
    "timestamp":1611751876000,  
    "originatingAddress":"+86666666",  
    "body":"我是信息内容",  
    "subId":0  
    }
  • timestamp 接收的时间

  • originatingAddress 发送者的号码

  • body 信息内容

  • subId 卡槽下标

注意事项

  • 使用前,请确认已经开通 短信读取权限接收新短信权限
  • 如果没有开通,请引导用户进行授权,可建议使用这个插件 App权限判断和提示,进行判断开启

java 核心源代码

package io.king.uniplugin;  

import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
import android.os.Build;  
import android.os.Bundle;  
import android.provider.Telephony;  
import android.telephony.SmsMessage;  
import android.util.Log;  

import java.lang.reflect.Method;  
import java.util.HashMap;  
import java.util.Map;  

public class SmsReceiver extends BroadcastReceiver {  

    public static final String TAG = "SmsListenerPackage";  
    public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";  

    private void receiveMessages(SmsMessage[] messages) throws Exception {  
        if (messages == null) {  
            return;  
        }  

        Class ownerClass = Class.forName("android.telephony.SmsMessage");  
        Method method = ownerClass.getMethod("getSubId");  

        Map<String, String> msg = new HashMap<String, String>(messages.length);  
        Map<String, Integer> msgSubId = new HashMap<String, Integer>(messages.length);  
        Map<String, Long> msgTime = new HashMap<String, Long>(messages.length);  
        for (SmsMessage message : messages) {  
            String originatingAddress = message.getOriginatingAddress();  

            // Check if index with number exists  
            if (!msg.containsKey(originatingAddress)) {  
                msg.put(originatingAddress, message.getMessageBody());  
                int subId = (int) method.invoke(message);  
                msgSubId.put(originatingAddress, subId);  
                msgTime.put(originatingAddress, message.getTimestampMillis());  
            } else {  
                String previousParts = msg.get(originatingAddress);  
                String msgString = previousParts + message.getMessageBody();  
                msg.put(originatingAddress, msgString);  
            }  
        }  

        for (String sender : msg.keySet()) {  
            Log.d(  
                    TAG,  
                    String.format("%s: %s", sender, msg.get(sender))  
            );  

            Map<String, Object> receivedMessage = new HashMap<>();  

            receivedMessage.put("originatingAddress", sender);  
            receivedMessage.put("body", msg.get(sender));  
            receivedMessage.put("timestamp", msgTime.get(sender));  
            receivedMessage.put("subId", msgSubId.get(sender));  

            if (CallBack.getInstance().customizeNotifyMessage != null) {  
                CallBack.getInstance().customizeNotifyMessage.onCustomizeNotifyMessage(receivedMessage);  
            }  
        }  
    }  

    @Override  
    public void onReceive(Context context, Intent intent) {  
        SmsMessage[] messages = null;  

        if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {  
            try {  
                final Bundle bundle = intent.getExtras();  

                if (bundle == null || !bundle.containsKey("pdus")) {  
                    return;  
                }  

                final Object[] pdus = (Object[]) bundle.get("pdus");  
                messages = new SmsMessage[pdus.length];  

                for (int i = 0; i < pdus.length; i++) {  
                    byte[] pdu = (byte[]) pdus[i];  
                    messages[i] = SmsMessage.createFromPdu(pdu);  
                    Log.e(TAG,  messages[i].getMessageBody());  
                }  

            } catch (Exception e) {  
                Log.e(TAG, e.getMessage());  
            }  
        }  

        try {  
            receiveMessages(messages);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}
继续阅读 »

监听手机短信

实时监控手机收到的短信,可获取到发送者的手机号、时间、内容、卡槽等相关信息

使用方法

  • 下载本插件并存放到nativeplugins目录下

  • 在页面中引入这个插件

    // 监听短信插件  
    const kingReceiceSmsModule = uni.requireNativePlugin("king-receive-sms")  
  • 调用插件的方法

    kingReceiceSmsModule.addCustomizeNotifyMessage(result => {  
        <!-- result 为监听到的信息 -->  
        var str = JSON.stringify(result);  
        console.log(str)  
    });  

    信息格式

    {  
    "timestamp":1611751876000,  
    "originatingAddress":"+86666666",  
    "body":"我是信息内容",  
    "subId":0  
    }
  • timestamp 接收的时间

  • originatingAddress 发送者的号码

  • body 信息内容

  • subId 卡槽下标

注意事项

  • 使用前,请确认已经开通 短信读取权限接收新短信权限
  • 如果没有开通,请引导用户进行授权,可建议使用这个插件 App权限判断和提示,进行判断开启

java 核心源代码

package io.king.uniplugin;  

import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
import android.os.Build;  
import android.os.Bundle;  
import android.provider.Telephony;  
import android.telephony.SmsMessage;  
import android.util.Log;  

import java.lang.reflect.Method;  
import java.util.HashMap;  
import java.util.Map;  

public class SmsReceiver extends BroadcastReceiver {  

    public static final String TAG = "SmsListenerPackage";  
    public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";  

    private void receiveMessages(SmsMessage[] messages) throws Exception {  
        if (messages == null) {  
            return;  
        }  

        Class ownerClass = Class.forName("android.telephony.SmsMessage");  
        Method method = ownerClass.getMethod("getSubId");  

        Map<String, String> msg = new HashMap<String, String>(messages.length);  
        Map<String, Integer> msgSubId = new HashMap<String, Integer>(messages.length);  
        Map<String, Long> msgTime = new HashMap<String, Long>(messages.length);  
        for (SmsMessage message : messages) {  
            String originatingAddress = message.getOriginatingAddress();  

            // Check if index with number exists  
            if (!msg.containsKey(originatingAddress)) {  
                msg.put(originatingAddress, message.getMessageBody());  
                int subId = (int) method.invoke(message);  
                msgSubId.put(originatingAddress, subId);  
                msgTime.put(originatingAddress, message.getTimestampMillis());  
            } else {  
                String previousParts = msg.get(originatingAddress);  
                String msgString = previousParts + message.getMessageBody();  
                msg.put(originatingAddress, msgString);  
            }  
        }  

        for (String sender : msg.keySet()) {  
            Log.d(  
                    TAG,  
                    String.format("%s: %s", sender, msg.get(sender))  
            );  

            Map<String, Object> receivedMessage = new HashMap<>();  

            receivedMessage.put("originatingAddress", sender);  
            receivedMessage.put("body", msg.get(sender));  
            receivedMessage.put("timestamp", msgTime.get(sender));  
            receivedMessage.put("subId", msgSubId.get(sender));  

            if (CallBack.getInstance().customizeNotifyMessage != null) {  
                CallBack.getInstance().customizeNotifyMessage.onCustomizeNotifyMessage(receivedMessage);  
            }  
        }  
    }  

    @Override  
    public void onReceive(Context context, Intent intent) {  
        SmsMessage[] messages = null;  

        if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {  
            try {  
                final Bundle bundle = intent.getExtras();  

                if (bundle == null || !bundle.containsKey("pdus")) {  
                    return;  
                }  

                final Object[] pdus = (Object[]) bundle.get("pdus");  
                messages = new SmsMessage[pdus.length];  

                for (int i = 0; i < pdus.length; i++) {  
                    byte[] pdu = (byte[]) pdus[i];  
                    messages[i] = SmsMessage.createFromPdu(pdu);  
                    Log.e(TAG,  messages[i].getMessageBody());  
                }  

            } catch (Exception e) {  
                Log.e(TAG, e.getMessage());  
            }  
        }  

        try {  
            receiveMessages(messages);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}
收起阅读 »

提供兼职实习岗位(前端)

此贴发布于2021年1月27日
有效期10天
到2021年2月7号后失效

本人运营了一个电商类型的网站.目前有4个项目

  • 移动端 uni-app + ts
  • pc端 vue3.x + ts
  • 管理后台1 uni-cloud-admin + ts + uni-clound-db
  • 管理后台2 react + ts + 原生uni-cloud

目前全部是自己开发.由于还在上班.精力不够.找1到2个学生或者初级前端一起开发

每个月1000到1500的补贴
更重要的是
带着你一起熟悉正规互联网公司的开发流程

要求
有一定的前端开发基础
好学
吃苦

需要回答以下几个问题
js和vue的区别
uni-app和vue的区别
uni-cloud和restfull的区别
你的前端职业规划
如果你没用过ts,你计划怎么学习

有意者加微信ranwawag

继续阅读 »

此贴发布于2021年1月27日
有效期10天
到2021年2月7号后失效

本人运营了一个电商类型的网站.目前有4个项目

  • 移动端 uni-app + ts
  • pc端 vue3.x + ts
  • 管理后台1 uni-cloud-admin + ts + uni-clound-db
  • 管理后台2 react + ts + 原生uni-cloud

目前全部是自己开发.由于还在上班.精力不够.找1到2个学生或者初级前端一起开发

每个月1000到1500的补贴
更重要的是
带着你一起熟悉正规互联网公司的开发流程

要求
有一定的前端开发基础
好学
吃苦

需要回答以下几个问题
js和vue的区别
uni-app和vue的区别
uni-cloud和restfull的区别
你的前端职业规划
如果你没用过ts,你计划怎么学习

有意者加微信ranwawag

收起阅读 »

最近程序员频繁被抓,如何避免面向监狱编程?

法律科普

最近,有很多关于程序员被抓甚至被判刑的新闻在朋友圈疯传:
"某程序员因为接了个外包,帮别人写了个软件,结果这个软件被用于赌博导致被抓。
某公司利用爬虫抓取用户信息,最后被发现,导致该公司的程序员被抓。
某P2P公司暴雷,老板跑路,程序员被抓。
中科大博士卖“外挂”非法牟利300多万,被警方逮捕。"

那么,作为一个程序员,如何避免这些坑呢?怎样尽可能的保护自己呢?
为此,作者特地找自己法律专业的朋友了解了一些常见的问题,如参与爬虫、赌博网站、P2P以及外挂开发是否违法等问题。

总结出了这篇文章,一起探讨一下"技术到底是不是真的无罪?",作为程序员如何避免面向监狱编程!
由于作者并非专业的法律工作从业者,文中法规部分的引用如有偏差,请指正。希望通过本文可以帮助广大程序员们了解一下有哪些自己的人身自由息息相关的坑。

一、爬虫

爬虫,是互联网时代一项普遍运用的网络信息搜集技术。该项技术最早应用于搜索引擎领域,是搜索引擎获取数据来源的支撑性技术之一。

随着数据资源的爆炸式增长,网络爬虫的应用场景和商业模式变得更加广泛和多样,较为常见的有新闻平台的内容汇聚和生成、电子商务平台的价格对比功能、基于气象数据的天气预报应用等等。

网络爬虫技术为数据收集者提供了极大的便利,也给专业网络爬虫公司带来巨大的收益。所以,很多公司都会有爬虫部门,或者负责开发爬虫的团队,在招聘网站上,也随处可见关于"爬虫工程师"的招聘贴。

关于这个问题,一直都是比较难定性的,因为爬虫本身只是个工具,就和菜刀一样,所以很多人都拿"菜刀无罪论"、"技术无罪论"来为爬虫辩护。

从网络爬虫的相关案例来看,爬虫的开发及使用者通常有很多理由为自己辩护:

“我爬取的都是这个网站的公开数据,搜索引擎不也是这么做的吗?”

“这与搜索引擎行为类似,只是使用了自动脚本,这是合理使用行为。”

“我已经遵守了它们的robots协议、该网站没有robots协议”

“这些数据我只是个人研究使用,并没有商业目的”。

那么,爬虫到底犯不犯法?

目前,关于网络爬虫相关的约束,主要是2019年05月28日国家网信办发布的《数据安全管理办法(征求意见稿)》。这份文件主要包含了数据收集、数据处理使用以及数据安全监督管理三个章节。

基本可以确定的是,如果爬虫使用不当,那么爬虫的开发者是有可能触犯法律的,而根据情况不同,获得的刑罚也有可能有差异。

要看开发和使用爬虫是否犯法,需要从爬什么数据、如何爬取数据以及爬到数据之后怎么用三个方面来判断。接下来就简单分析一下:

爬什么数据犯法?

1、属于著作权法保护的作品

有些网站发表的内容,如文章、评论等都是有著作权的,如果只是单纯的通过浏览器查看是不会触犯法律的。

但是,对于有著作权的作品,如果未经著作权人许可,以盈利为目的,对其作品进行复制是会触犯法律的。

根据《中华人民共和国著作权法》第46条:有下列侵权行为的,应当根据情况,承担停止侵害、消除影响、公开赔礼道歉、赔偿损失等民事责任,并可以由著作权行政管理部门给予没收非法所得、罚款等行政处罚:(一)剽窃、抄袭他人作品的;(二)未经著作权人许可,以营利为目的,复制发行其作品的;(三)出版他人享有专有出版权的图书的;(四)未经表演者许可,对其表演制作录音录像出版的;(五)未经录音录像制作者许可,复制发行其制作的录音录像的;(六)未经广播电台、电视台许可,复制发行其制作的广播、电视节目的;(七)制作、出售假冒他人署名的美术作品的。

如果是使用爬虫技术手段爬取数据之后将其保存下来或者传播,并且进行盈利,这种都是属于犯罪的。

2、用户的个人信息或者个人隐私

个人用户的个人信息,即使是用户自己放到一些网站上进行公开或者部分公开,如微博、微信等,不代表这些数据就可以被其他人随便获取!

根据《民法总则》第111条:任何组织和个人需要获取他人个人信息的,应当依法取得并确保信息安全。不得非法收集、使用、加工、传输他人个人信息;
根据《网络安全法》第44条:任何个人和组织不得窃取或者以其他非法方式获取个人信息。因此,如果爬虫在未经用户同意的情况下大量抓取用户的个人信息,则有可能构成非法收集个人信息的违法行为。

所以,如果爬取的数据涉及到个人信息,都是违法的!

还有些爬虫企图绕过权限校验等,爬取用户未公开的信息,如个人私密相册照片等,都是属于侵犯用户的个人隐私的,这种也是违法的。

3、反不正当竞争保护的数据

目前有很多网站中的数据系由用户生成,且该等数据和内容系原告网站的主要竞争力来源。如大众点评上面的店铺评价、评论等信息,携程网上面的关于酒店的评价评论等信息等。

根据《反不正当竞争法》第2条:经营者在市场交易中,应当遵循自愿、平等、公平、诚实信用的原则,遵守公认的商业道德。

那么,未经允许,爬取其他网站的核心数据,很明显并没有遵守《反不正当竞争法》中规定的自愿、平等、公平、诚实信用的原则。
在大众点评诉百度不正当竞争案件、以及新浪微博诉脉脉不正当竞争等案件中,法院都认定被告未经许可抓取、使用原告网站中的数据的行为,违反了诚实信用原则及公认的道德,损害了互联网的市场竞争秩序,损害了原告的竞争优势,从而构成不正当竞争。

因此,如果抓取大众点评、微博、豆瓣电影、知乎等UGC模式的网站上用户发布的信息,并在自己的产品或者服务中发布、使用该等信息,则有较大的风险构成不正当竞争。

怎么爬犯法?

如果是爬取公开的数据,通常不会被认为是侵权。Google、百度等搜索引擎都是这么爬取的。

那么,到底怎么爬数据是有可能触犯法律的呢,主要考虑是否涉及以下两种行为:

未遵守Robots协议

Robots协议是技术界为了解决爬取方和被爬取方之间通过计算机程序完成关于爬取的意愿沟通而产生的一种机制。

根据《互联网搜索引擎服务自律公约》第7条:机器人协议(robots协议)是指互联网站所有者使用robots.txt文件,向网络机器人(Web robots)给出网站指令的协议。具体而言,robots协议是网站所有者通过位于置于网站根目录下的文本文件robots.txt,提示网络机器人哪些网页不应被抓取,哪些网页可以抓取。

根据《互联网搜索引擎服务自律公约》第8条:互联网站所有者设置机器人协议应遵循公平、开放和促进信息自由流动的原则,限制搜索引擎抓取应有行业公认合理的正当理由,不利用机器人协议进行不正当竞争行为,积极营造鼓励创新、公平公正的良性竞争环境。

虽然《互联网搜索引擎服务自律公约》仅适用于中国互联网协会会员单位和自愿加入《中国互联网行业自律公约》的互联网从业单位,但在司法实践中,Robots协议已经被认定构成互联网行业搜索领域内的商业道德。

因此,无视网站设置的Robots协议而随意抓取网站内容的行为将涉嫌构成对《反不正当竞争法》的第2条的违反,即违反诚实信用原则和商业道德的不正当竞争行为。

绕过防护措施对数据的访问,强行突破反爬措施

由于爬虫的批量访问会给网站带来巨大的压力和负担,因此许多网站经营者会采取技术手段,以阻止爬虫批量获取自己网站信息。

所以,很多爬虫工具为了爬取数据,会想办法通过各种手段绕过防护措施,但是,这种行为也是会触犯法律的。

根据《刑法》第285条第二款:违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。

企图通过技术手段,绕过网站的反爬机制,都属于《刑法》中规定的"侵入",都是要被处罚的。

怎么用犯法?

很多公司开发的爬虫遵守了Robots协议,也没有爬取不该爬取的数据,难道这样获取到的数据就可以随便使用了吗?其实也不是,如果使用不当,也会触犯法律的。

比如通过爬虫抓取到的数据进行盈利、损害他人利益、造假、诽谤等都是可能触犯法律的。

此外,未经被收集者同意,即使是将合法收集的公民个人信息向他人提供的,也属于刑法第二百五十三条之一规定的“提供公民个人信息”,可能构成犯罪。

小结

在使用爬虫的过程中,爬取的数据类型、爬取数据的方式以及爬取之后的使用都是可能触犯法律的。

其中,使用爬虫得到的数据进行盈利、损害他人利益、不正当竞争等一般都是针对经营者的。

但是对于程序员来说,如果你的老板让你开发的爬虫,是用来爬取用户的个人信息或者个人隐私,并且该爬虫未遵循Robots协议、或者有意的躲避反爬机制就可能触犯到法律了。

二、赌博、S情网站

除了爬虫以外,最近很多关于程序员参与赌博网站的开发,最终被判刑的新闻,那么,如果参与赌博、S情等网站的开发,是不是一定触犯法律呢?
这种情况主要看开发者是不是属于"明知故犯"。

根据《最高人民法院、最高人民检察院、公安部关于办理网络赌博犯罪案件适用法律若干问题的意见》中关于网上开设赌场共同犯罪的认定和处罚规定:

明知是赌博网站,而为其提供下列服务或者帮助的,属于开设赌场罪的共同犯罪,依照刑法第三百零三条第二款的规定处罚:

(一)为赌博网站提供互联网接入、服务器托管、网络存储空间、通讯传输通道、投放广告、发展会员、软件开发、技术支持等服务,收取服务费数额在2万元以上的;

(二)为赌博网站提供资金支付结算服务,收取服务费数额在1万元以上或者帮助收取赌资20万元以上的;

(三)为10个以上赌博网站投放与网址、赔率等信息有关的广告或者为赌博网站投放广告累计100条以上的。

也就是说,如果你作为程序员,你在帮公司开发赌博网站,只要公司付给你的费用超过了2万元以上,那么你就和开设赌场的人是共同犯罪。

除了赌博网站,所有和黄赌毒有关的软件开发都不要参与,明知道是违法或者可能违法的行为,并为其提供技术支持,都是有可能触犯法律的。快播不就是个很好的例子吗。
所以,程序员一定要远离赌博、色情等网站,并拒绝为他们提供技术服务。

三、P2P

最近,P2P频繁暴雷,因为是网络借贷,所以这些暴雷的公司必然是有程序员的,所以,对于这种P2P公司如果涉及违法,那么参与开发的程序员到底算不算从犯?

前段时间,有脉脉用户发帖称"P2P公司暴雷,前端程序员被抓":

一时间,引起了广泛的讨论,有人认为程序员为违法提供了帮助,属于从犯,有人认为程序员可能不知道公司违法,是"不知者不罪"

那么,关于这个情况,知乎上有用户给过专业的解答:

『如果程序员只是单纯的负责开发,只拿合理的死工资,本人对于公司的合法性和P2P的政策不了解,找工作也是通过正规渠道的。』那么就不算从犯。

但是,如果还负责了公司的其他事情,或者没有只拿死工资,找工作也不是正规渠道的,那就另当别论了。重要的是,如果自己明知道公司是非法的,那么肯定就涉及犯罪了。

所以,对于这种做互联网金融的企业的程序员,需要多多了解一下自己公司当前的主营业务是否合法。是否涉及到非法集资、传销等违法行为。

四、外挂

外挂是指利用电脑技术针对一个或多个网络游戏,通过改变软件的部分程序制作而成的作弊程序。制作贩卖游戏外挂也是会受到我国司法机关打击的行为。

根据开发者制作的不同的外挂类型,以及使用方式等,根据以往案例,可能触犯非法经营罪、破坏计算机信息系统罪以及侵犯著作权罪等。

非法经营罪

外挂等违法行为的出现,严重侵害了游戏开发者、运营商以及正常消费者的合法权益,扰乱了互联网游戏经营的正常秩序,破坏了网络游戏产业的良性发展,违反国家规定,情节严重,应按刑法第225条第四项的规定处罚。

根据《刑法》第225条:违反国家规定,有下列非法经营行为之一,扰乱市场秩序,情节严重的,处五年以下有期徒刑或者拘役,并处或者单处违法所得一倍以上五倍以下罚金;情节特别严重的,处五年以上有期徒刑,并处违法所得一倍以上五倍以下罚金或者没收财产:

一)未经许可经营法律、行政法规规定的专营、专卖物品或者其他限制买卖的物品的;

二)买卖进出口许可证、进出口原产地证明以及其他法律、行政法规规定的经营许可证或者批准文件的;

三)未经国家有关主管部门批准非法经营证券、期货、保险业务的,或者非法从事资金支付结算业务的;

四)其他严重扰乱市场秩序的非法经营行为。

破坏计算机信息系统罪

有些外挂会修改网络游戏运行数据、干扰网络游戏服务端计算机信息系统功能、危害计算机信息系统安全的行为,符合破坏计算机信息系统罪的犯罪构成要件。

根据《刑法》第286条:违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行,后果严重的,处五年以下有期徒刑或者拘役;后果特别严重的,处五年以上有期徒刑。

侵犯著作权罪

还有些开发者通过非法手段,获取他人享有著作权的计算机软件中的核心程序文件,制作外挂后用以牟利。这种外挂程序虽然与官方客户端程序并不完全一致,但主体结构、功能构成实质性相同,故被告人的行为构成非法复制计算机软件的行为,应以侵犯著作权罪定罪处罚。

根据《刑法》第217条:以营利为目的,有下列侵犯著作权情形之一,违法所得数额较大或者有其他严重情节的,处三年以下有期徒刑或者拘役,并处或者单处罚金;违法所得数额巨大或者具有其他特别严重情节的,处三年以上七年以下有期徒刑,并处罚金:

1、未经著作权人许可,复制发行其文字作品、音乐、电影、电视、录像作品、计算机软件及其他作品 的;

2、出版他人享有专有出版权的图书的;

3、未经录音录像制作者许可,复制发行其制作的录音录像的;

4、制作、出售假冒他人署名的美术作品的。

根据《刑法》第218条:以营利为目的,销售明知是本法第二百一十七条规定的侵权复制品,违法所得数额巨大的,处三年以下有期徒刑或者拘役,并处或者单处罚金。

总结

对于广大爬虫工程师,如果你开发的爬虫涉及个人信息及隐私,爬虫未遵守Robots协议,爬虫企图通过技术手段绕过反爬机制等,都是触犯了法律的。

对于那些做爬虫的企业,如果涉及到爬取受著作权保护的内容,涉及到公司商业机密等内容,并且用于盈利或者不正当竞争等,也是国家法律所不允许的。

还有就是,"明知故犯"的事情不要做,也不要抱有任何侥幸心理,一定要远离赌博、S情网站,并拒绝为他们提供任何技术支持。

如果公司的主营业务是P2P,并且自己参与了P2P的开发,那么一定要了解清楚自己公司所做的业务是否合规,如果发现不合规,一定要趁早离职。并且不要参与除纯开发以外的其他事宜。

不要参与'外挂软件'的开发。学会保护自己!

如果你是文中介绍过的相关行业中的程序员,那么希望大家第一时间找律师咨询一下,自己是否有触及到法律,以及如何避免和脱身等。

本文只是简单介绍了几种常见的容易被坑的情况,还有很多情况正在发生和即将发生,所以,希望广大程序员们,不要只顾埋头写代码,还要经常抬头看看,审视下自己所做的产品、所在的公司以及所从事的行业。

作为程序员,我们手里的技术就是工具,那么,我们有责任也有义务来保证我们的工具是用在正途的。

最后,技术无罪、人会犯错、知错能改、善莫大焉。

参考资料:

网络爬虫涉及的法律问题(一)
爬虫的法律红线
https://www.zhihu.com/question/37767673

此文章转载自【程序员面试现场】微信公众号,如有不当联系删除。原文链接

继续阅读 »

最近,有很多关于程序员被抓甚至被判刑的新闻在朋友圈疯传:
"某程序员因为接了个外包,帮别人写了个软件,结果这个软件被用于赌博导致被抓。
某公司利用爬虫抓取用户信息,最后被发现,导致该公司的程序员被抓。
某P2P公司暴雷,老板跑路,程序员被抓。
中科大博士卖“外挂”非法牟利300多万,被警方逮捕。"

那么,作为一个程序员,如何避免这些坑呢?怎样尽可能的保护自己呢?
为此,作者特地找自己法律专业的朋友了解了一些常见的问题,如参与爬虫、赌博网站、P2P以及外挂开发是否违法等问题。

总结出了这篇文章,一起探讨一下"技术到底是不是真的无罪?",作为程序员如何避免面向监狱编程!
由于作者并非专业的法律工作从业者,文中法规部分的引用如有偏差,请指正。希望通过本文可以帮助广大程序员们了解一下有哪些自己的人身自由息息相关的坑。

一、爬虫

爬虫,是互联网时代一项普遍运用的网络信息搜集技术。该项技术最早应用于搜索引擎领域,是搜索引擎获取数据来源的支撑性技术之一。

随着数据资源的爆炸式增长,网络爬虫的应用场景和商业模式变得更加广泛和多样,较为常见的有新闻平台的内容汇聚和生成、电子商务平台的价格对比功能、基于气象数据的天气预报应用等等。

网络爬虫技术为数据收集者提供了极大的便利,也给专业网络爬虫公司带来巨大的收益。所以,很多公司都会有爬虫部门,或者负责开发爬虫的团队,在招聘网站上,也随处可见关于"爬虫工程师"的招聘贴。

关于这个问题,一直都是比较难定性的,因为爬虫本身只是个工具,就和菜刀一样,所以很多人都拿"菜刀无罪论"、"技术无罪论"来为爬虫辩护。

从网络爬虫的相关案例来看,爬虫的开发及使用者通常有很多理由为自己辩护:

“我爬取的都是这个网站的公开数据,搜索引擎不也是这么做的吗?”

“这与搜索引擎行为类似,只是使用了自动脚本,这是合理使用行为。”

“我已经遵守了它们的robots协议、该网站没有robots协议”

“这些数据我只是个人研究使用,并没有商业目的”。

那么,爬虫到底犯不犯法?

目前,关于网络爬虫相关的约束,主要是2019年05月28日国家网信办发布的《数据安全管理办法(征求意见稿)》。这份文件主要包含了数据收集、数据处理使用以及数据安全监督管理三个章节。

基本可以确定的是,如果爬虫使用不当,那么爬虫的开发者是有可能触犯法律的,而根据情况不同,获得的刑罚也有可能有差异。

要看开发和使用爬虫是否犯法,需要从爬什么数据、如何爬取数据以及爬到数据之后怎么用三个方面来判断。接下来就简单分析一下:

爬什么数据犯法?

1、属于著作权法保护的作品

有些网站发表的内容,如文章、评论等都是有著作权的,如果只是单纯的通过浏览器查看是不会触犯法律的。

但是,对于有著作权的作品,如果未经著作权人许可,以盈利为目的,对其作品进行复制是会触犯法律的。

根据《中华人民共和国著作权法》第46条:有下列侵权行为的,应当根据情况,承担停止侵害、消除影响、公开赔礼道歉、赔偿损失等民事责任,并可以由著作权行政管理部门给予没收非法所得、罚款等行政处罚:(一)剽窃、抄袭他人作品的;(二)未经著作权人许可,以营利为目的,复制发行其作品的;(三)出版他人享有专有出版权的图书的;(四)未经表演者许可,对其表演制作录音录像出版的;(五)未经录音录像制作者许可,复制发行其制作的录音录像的;(六)未经广播电台、电视台许可,复制发行其制作的广播、电视节目的;(七)制作、出售假冒他人署名的美术作品的。

如果是使用爬虫技术手段爬取数据之后将其保存下来或者传播,并且进行盈利,这种都是属于犯罪的。

2、用户的个人信息或者个人隐私

个人用户的个人信息,即使是用户自己放到一些网站上进行公开或者部分公开,如微博、微信等,不代表这些数据就可以被其他人随便获取!

根据《民法总则》第111条:任何组织和个人需要获取他人个人信息的,应当依法取得并确保信息安全。不得非法收集、使用、加工、传输他人个人信息;
根据《网络安全法》第44条:任何个人和组织不得窃取或者以其他非法方式获取个人信息。因此,如果爬虫在未经用户同意的情况下大量抓取用户的个人信息,则有可能构成非法收集个人信息的违法行为。

所以,如果爬取的数据涉及到个人信息,都是违法的!

还有些爬虫企图绕过权限校验等,爬取用户未公开的信息,如个人私密相册照片等,都是属于侵犯用户的个人隐私的,这种也是违法的。

3、反不正当竞争保护的数据

目前有很多网站中的数据系由用户生成,且该等数据和内容系原告网站的主要竞争力来源。如大众点评上面的店铺评价、评论等信息,携程网上面的关于酒店的评价评论等信息等。

根据《反不正当竞争法》第2条:经营者在市场交易中,应当遵循自愿、平等、公平、诚实信用的原则,遵守公认的商业道德。

那么,未经允许,爬取其他网站的核心数据,很明显并没有遵守《反不正当竞争法》中规定的自愿、平等、公平、诚实信用的原则。
在大众点评诉百度不正当竞争案件、以及新浪微博诉脉脉不正当竞争等案件中,法院都认定被告未经许可抓取、使用原告网站中的数据的行为,违反了诚实信用原则及公认的道德,损害了互联网的市场竞争秩序,损害了原告的竞争优势,从而构成不正当竞争。

因此,如果抓取大众点评、微博、豆瓣电影、知乎等UGC模式的网站上用户发布的信息,并在自己的产品或者服务中发布、使用该等信息,则有较大的风险构成不正当竞争。

怎么爬犯法?

如果是爬取公开的数据,通常不会被认为是侵权。Google、百度等搜索引擎都是这么爬取的。

那么,到底怎么爬数据是有可能触犯法律的呢,主要考虑是否涉及以下两种行为:

未遵守Robots协议

Robots协议是技术界为了解决爬取方和被爬取方之间通过计算机程序完成关于爬取的意愿沟通而产生的一种机制。

根据《互联网搜索引擎服务自律公约》第7条:机器人协议(robots协议)是指互联网站所有者使用robots.txt文件,向网络机器人(Web robots)给出网站指令的协议。具体而言,robots协议是网站所有者通过位于置于网站根目录下的文本文件robots.txt,提示网络机器人哪些网页不应被抓取,哪些网页可以抓取。

根据《互联网搜索引擎服务自律公约》第8条:互联网站所有者设置机器人协议应遵循公平、开放和促进信息自由流动的原则,限制搜索引擎抓取应有行业公认合理的正当理由,不利用机器人协议进行不正当竞争行为,积极营造鼓励创新、公平公正的良性竞争环境。

虽然《互联网搜索引擎服务自律公约》仅适用于中国互联网协会会员单位和自愿加入《中国互联网行业自律公约》的互联网从业单位,但在司法实践中,Robots协议已经被认定构成互联网行业搜索领域内的商业道德。

因此,无视网站设置的Robots协议而随意抓取网站内容的行为将涉嫌构成对《反不正当竞争法》的第2条的违反,即违反诚实信用原则和商业道德的不正当竞争行为。

绕过防护措施对数据的访问,强行突破反爬措施

由于爬虫的批量访问会给网站带来巨大的压力和负担,因此许多网站经营者会采取技术手段,以阻止爬虫批量获取自己网站信息。

所以,很多爬虫工具为了爬取数据,会想办法通过各种手段绕过防护措施,但是,这种行为也是会触犯法律的。

根据《刑法》第285条第二款:违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。

企图通过技术手段,绕过网站的反爬机制,都属于《刑法》中规定的"侵入",都是要被处罚的。

怎么用犯法?

很多公司开发的爬虫遵守了Robots协议,也没有爬取不该爬取的数据,难道这样获取到的数据就可以随便使用了吗?其实也不是,如果使用不当,也会触犯法律的。

比如通过爬虫抓取到的数据进行盈利、损害他人利益、造假、诽谤等都是可能触犯法律的。

此外,未经被收集者同意,即使是将合法收集的公民个人信息向他人提供的,也属于刑法第二百五十三条之一规定的“提供公民个人信息”,可能构成犯罪。

小结

在使用爬虫的过程中,爬取的数据类型、爬取数据的方式以及爬取之后的使用都是可能触犯法律的。

其中,使用爬虫得到的数据进行盈利、损害他人利益、不正当竞争等一般都是针对经营者的。

但是对于程序员来说,如果你的老板让你开发的爬虫,是用来爬取用户的个人信息或者个人隐私,并且该爬虫未遵循Robots协议、或者有意的躲避反爬机制就可能触犯到法律了。

二、赌博、S情网站

除了爬虫以外,最近很多关于程序员参与赌博网站的开发,最终被判刑的新闻,那么,如果参与赌博、S情等网站的开发,是不是一定触犯法律呢?
这种情况主要看开发者是不是属于"明知故犯"。

根据《最高人民法院、最高人民检察院、公安部关于办理网络赌博犯罪案件适用法律若干问题的意见》中关于网上开设赌场共同犯罪的认定和处罚规定:

明知是赌博网站,而为其提供下列服务或者帮助的,属于开设赌场罪的共同犯罪,依照刑法第三百零三条第二款的规定处罚:

(一)为赌博网站提供互联网接入、服务器托管、网络存储空间、通讯传输通道、投放广告、发展会员、软件开发、技术支持等服务,收取服务费数额在2万元以上的;

(二)为赌博网站提供资金支付结算服务,收取服务费数额在1万元以上或者帮助收取赌资20万元以上的;

(三)为10个以上赌博网站投放与网址、赔率等信息有关的广告或者为赌博网站投放广告累计100条以上的。

也就是说,如果你作为程序员,你在帮公司开发赌博网站,只要公司付给你的费用超过了2万元以上,那么你就和开设赌场的人是共同犯罪。

除了赌博网站,所有和黄赌毒有关的软件开发都不要参与,明知道是违法或者可能违法的行为,并为其提供技术支持,都是有可能触犯法律的。快播不就是个很好的例子吗。
所以,程序员一定要远离赌博、色情等网站,并拒绝为他们提供技术服务。

三、P2P

最近,P2P频繁暴雷,因为是网络借贷,所以这些暴雷的公司必然是有程序员的,所以,对于这种P2P公司如果涉及违法,那么参与开发的程序员到底算不算从犯?

前段时间,有脉脉用户发帖称"P2P公司暴雷,前端程序员被抓":

一时间,引起了广泛的讨论,有人认为程序员为违法提供了帮助,属于从犯,有人认为程序员可能不知道公司违法,是"不知者不罪"

那么,关于这个情况,知乎上有用户给过专业的解答:

『如果程序员只是单纯的负责开发,只拿合理的死工资,本人对于公司的合法性和P2P的政策不了解,找工作也是通过正规渠道的。』那么就不算从犯。

但是,如果还负责了公司的其他事情,或者没有只拿死工资,找工作也不是正规渠道的,那就另当别论了。重要的是,如果自己明知道公司是非法的,那么肯定就涉及犯罪了。

所以,对于这种做互联网金融的企业的程序员,需要多多了解一下自己公司当前的主营业务是否合法。是否涉及到非法集资、传销等违法行为。

四、外挂

外挂是指利用电脑技术针对一个或多个网络游戏,通过改变软件的部分程序制作而成的作弊程序。制作贩卖游戏外挂也是会受到我国司法机关打击的行为。

根据开发者制作的不同的外挂类型,以及使用方式等,根据以往案例,可能触犯非法经营罪、破坏计算机信息系统罪以及侵犯著作权罪等。

非法经营罪

外挂等违法行为的出现,严重侵害了游戏开发者、运营商以及正常消费者的合法权益,扰乱了互联网游戏经营的正常秩序,破坏了网络游戏产业的良性发展,违反国家规定,情节严重,应按刑法第225条第四项的规定处罚。

根据《刑法》第225条:违反国家规定,有下列非法经营行为之一,扰乱市场秩序,情节严重的,处五年以下有期徒刑或者拘役,并处或者单处违法所得一倍以上五倍以下罚金;情节特别严重的,处五年以上有期徒刑,并处违法所得一倍以上五倍以下罚金或者没收财产:

一)未经许可经营法律、行政法规规定的专营、专卖物品或者其他限制买卖的物品的;

二)买卖进出口许可证、进出口原产地证明以及其他法律、行政法规规定的经营许可证或者批准文件的;

三)未经国家有关主管部门批准非法经营证券、期货、保险业务的,或者非法从事资金支付结算业务的;

四)其他严重扰乱市场秩序的非法经营行为。

破坏计算机信息系统罪

有些外挂会修改网络游戏运行数据、干扰网络游戏服务端计算机信息系统功能、危害计算机信息系统安全的行为,符合破坏计算机信息系统罪的犯罪构成要件。

根据《刑法》第286条:违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行,后果严重的,处五年以下有期徒刑或者拘役;后果特别严重的,处五年以上有期徒刑。

侵犯著作权罪

还有些开发者通过非法手段,获取他人享有著作权的计算机软件中的核心程序文件,制作外挂后用以牟利。这种外挂程序虽然与官方客户端程序并不完全一致,但主体结构、功能构成实质性相同,故被告人的行为构成非法复制计算机软件的行为,应以侵犯著作权罪定罪处罚。

根据《刑法》第217条:以营利为目的,有下列侵犯著作权情形之一,违法所得数额较大或者有其他严重情节的,处三年以下有期徒刑或者拘役,并处或者单处罚金;违法所得数额巨大或者具有其他特别严重情节的,处三年以上七年以下有期徒刑,并处罚金:

1、未经著作权人许可,复制发行其文字作品、音乐、电影、电视、录像作品、计算机软件及其他作品 的;

2、出版他人享有专有出版权的图书的;

3、未经录音录像制作者许可,复制发行其制作的录音录像的;

4、制作、出售假冒他人署名的美术作品的。

根据《刑法》第218条:以营利为目的,销售明知是本法第二百一十七条规定的侵权复制品,违法所得数额巨大的,处三年以下有期徒刑或者拘役,并处或者单处罚金。

总结

对于广大爬虫工程师,如果你开发的爬虫涉及个人信息及隐私,爬虫未遵守Robots协议,爬虫企图通过技术手段绕过反爬机制等,都是触犯了法律的。

对于那些做爬虫的企业,如果涉及到爬取受著作权保护的内容,涉及到公司商业机密等内容,并且用于盈利或者不正当竞争等,也是国家法律所不允许的。

还有就是,"明知故犯"的事情不要做,也不要抱有任何侥幸心理,一定要远离赌博、S情网站,并拒绝为他们提供任何技术支持。

如果公司的主营业务是P2P,并且自己参与了P2P的开发,那么一定要了解清楚自己公司所做的业务是否合规,如果发现不合规,一定要趁早离职。并且不要参与除纯开发以外的其他事宜。

不要参与'外挂软件'的开发。学会保护自己!

如果你是文中介绍过的相关行业中的程序员,那么希望大家第一时间找律师咨询一下,自己是否有触及到法律,以及如何避免和脱身等。

本文只是简单介绍了几种常见的容易被坑的情况,还有很多情况正在发生和即将发生,所以,希望广大程序员们,不要只顾埋头写代码,还要经常抬头看看,审视下自己所做的产品、所在的公司以及所从事的行业。

作为程序员,我们手里的技术就是工具,那么,我们有责任也有义务来保证我们的工具是用在正途的。

最后,技术无罪、人会犯错、知错能改、善莫大焉。

参考资料:

网络爬虫涉及的法律问题(一)
爬虫的法律红线
https://www.zhihu.com/question/37767673

此文章转载自【程序员面试现场】微信公众号,如有不当联系删除。原文链接

收起阅读 »

【建议】webview的listenResourceLoading增加返回response header信息

HTML5+

https://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject.listenResourceLoading

目前回调只返回url,但是很多时候,通过url无法判断资源类型,这就导致需要再次请求这个url去获取header里的content-type,请求两次,数量多的话,导致网络堵塞。
建议直接在回调里返回header信息。

继续阅读 »

https://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject.listenResourceLoading

目前回调只返回url,但是很多时候,通过url无法判断资源类型,这就导致需要再次请求这个url去获取header里的content-type,请求两次,数量多的话,导致网络堵塞。
建议直接在回调里返回header信息。

收起阅读 »

强烈建议插件市场中的插件提供历史版本下载

优化建议 用户建议 插件开发 分享插件

1、某些插件更新后可能会出现一些意外BUG,需要继续使用上一个版本。
2、有些开发者心态不好,原先开放下载的插件因为某些原因直接上传一个空插件,不提供他人下载。
3、不是所有的插件作者都使用github,就导致根本无法下载历史版本。

1、某些插件更新后可能会出现一些意外BUG,需要继续使用上一个版本。
2、有些开发者心态不好,原先开放下载的插件因为某些原因直接上传一个空插件,不提供他人下载。
3、不是所有的插件作者都使用github,就导致根本无法下载历史版本。

swiper 高度问题记录

需求:在各个平台实现swiper-item的自动高度,底部的"章节、详情、讨论"采用swiper制作的tab选项,可左右滑动。

思路:
1、css的计算属性calc。给swiper组件设置style="height: calc(100vh - 188upx);"
动态计算屏幕高度减去顶部的高度,在h5中测试没有问题,不知道在其它终端会怎么样,没测试过。

2、高度100%不生效应该是父元素没有高度的问题,在实际测试中顶层view设置为100vh,其它包裹的高度都为100%,则swiper-item的高度也会根据内容高度显示

3、nvue 中样式属性不支持百分比,使用 flex:1
可以给page设置:height: 100%;display: flex;flex-direction: column;再给swiper设置flex:1;然后在盒子里再放一个盒子,同样高度100%;然后给它设置overflow: auto;再在盒子里写内容,就行了。 这个没有测试过

4、https://ask.dcloud.net.cn/question/74184 这个通过计算属性获取屏幕高度

5、https://ask.dcloud.net.cn/article/205 这个通过uniapp的API获取高度

const sysInfo = uni.getSystemInfoSync()  
const w = sysInfo.screenWidth;  
const h = sysInfo.screenHeight;  
console.log(`mode > ${sysInfo.model} , info size > W:${w} H:${h}`)  

const screenW = plus.screen.width;  
const screenH = plus.screen.height;  
console.log(`screen size > W: ${screenW} H:${screenH}`);  

const resolutionW = plus.screen.resolutionWidth;  
const resolutionH = plus.screen.resolutionHeight;  
console.log(`resolution size > W:${resolutionW} H:${resolutionH}`)

6、为了兼容各端,建议字体单位为px、宽高为rpx、布局采用flex。参考官方文档:https://ask.dcloud.net.cn/article/35657

继续阅读 »

需求:在各个平台实现swiper-item的自动高度,底部的"章节、详情、讨论"采用swiper制作的tab选项,可左右滑动。

思路:
1、css的计算属性calc。给swiper组件设置style="height: calc(100vh - 188upx);"
动态计算屏幕高度减去顶部的高度,在h5中测试没有问题,不知道在其它终端会怎么样,没测试过。

2、高度100%不生效应该是父元素没有高度的问题,在实际测试中顶层view设置为100vh,其它包裹的高度都为100%,则swiper-item的高度也会根据内容高度显示

3、nvue 中样式属性不支持百分比,使用 flex:1
可以给page设置:height: 100%;display: flex;flex-direction: column;再给swiper设置flex:1;然后在盒子里再放一个盒子,同样高度100%;然后给它设置overflow: auto;再在盒子里写内容,就行了。 这个没有测试过

4、https://ask.dcloud.net.cn/question/74184 这个通过计算属性获取屏幕高度

5、https://ask.dcloud.net.cn/article/205 这个通过uniapp的API获取高度

const sysInfo = uni.getSystemInfoSync()  
const w = sysInfo.screenWidth;  
const h = sysInfo.screenHeight;  
console.log(`mode > ${sysInfo.model} , info size > W:${w} H:${h}`)  

const screenW = plus.screen.width;  
const screenH = plus.screen.height;  
console.log(`screen size > W: ${screenW} H:${screenH}`);  

const resolutionW = plus.screen.resolutionWidth;  
const resolutionH = plus.screen.resolutionHeight;  
console.log(`resolution size > W:${resolutionW} H:${resolutionH}`)

6、为了兼容各端,建议字体单位为px、宽高为rpx、布局采用flex。参考官方文档:https://ask.dcloud.net.cn/article/35657

收起阅读 »

关于uniapp组件覆盖的问题记录

需求:顶部标题、标题下拉筛选菜单、再下面图文列表

问题:下拉菜单滑动时将顶部标题覆盖了

思路方向:
1、遇见问题不要慌:
A、第一条路:查各种技术文档;
B、第二条路:debug测试
C、第三条路:简化所有代码,简化到问题的关键点测试、查资料

2、查看z-index设置,且z-index仅能在定位元素上奏效(例如 position:absolute),可审查dom;
postion的定位包括:static、relative、absolute、fixed
z-index只能在position属性值为relative、absolute、fixed元素上有效。
https://www.cnblogs.com/zhuzhenwei918/p/6112034.html 深入理解css中position属性及z-index属性
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html Flex 布局教程:语法篇

3、z-index只在并行的组件上有效,一个组件包涵在另一个组件里设置z-index就要注意了

4、可用titleNView或用uni-ui的导航栏组件和list组件

5、如果用自定义导航,跨端需要检测顶部高度,这个还没测试过。

6、cover-view组件

继续阅读 »

需求:顶部标题、标题下拉筛选菜单、再下面图文列表

问题:下拉菜单滑动时将顶部标题覆盖了

思路方向:
1、遇见问题不要慌:
A、第一条路:查各种技术文档;
B、第二条路:debug测试
C、第三条路:简化所有代码,简化到问题的关键点测试、查资料

2、查看z-index设置,且z-index仅能在定位元素上奏效(例如 position:absolute),可审查dom;
postion的定位包括:static、relative、absolute、fixed
z-index只能在position属性值为relative、absolute、fixed元素上有效。
https://www.cnblogs.com/zhuzhenwei918/p/6112034.html 深入理解css中position属性及z-index属性
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html Flex 布局教程:语法篇

3、z-index只在并行的组件上有效,一个组件包涵在另一个组件里设置z-index就要注意了

4、可用titleNView或用uni-ui的导航栏组件和list组件

5、如果用自定义导航,跨端需要检测顶部高度,这个还没测试过。

6、cover-view组件

收起阅读 »

iOS报SSZipArchive 库找不到问题

Hbuilder SDK 2.7.4升级到3.0.5,iOS Xcode14打包报找不到 SSZipArchive 包的问题;
解决办法需要引入lib中的libcoreSupport.a包;

Hbuilder SDK 2.7.4升级到3.0.5,iOS Xcode14打包报找不到 SSZipArchive 包的问题;
解决办法需要引入lib中的libcoreSupport.a包;

vue3聊天网页版|Vue3.x+ElementPlus仿QQ|微信聊天界面

项目简介

一周前有给大家分享一个vue3版手机端聊天实战项目。今天给大家带来的是基于vue3.x+饿了么vue3组件库开发的pc桌面端仿制微信+QQ界面聊天|朋友圈实例。

vue3.0仿微信app界面聊天室

img

vue3-webchat 聊天实例支持发送图文消息、预览视频/图片、网址查看、拖拽发送图片、红包/朋友圈等功能。

QQ皮肤效果
img

微信皮肤效果
img

使用技术

  • 编辑器:VScode
  • MVVM框架:Vue3.0.5
  • 状态管理:Vuex4.x
  • 页面路由:Vue-Router@4
  • UI组件库:element-plus (饿了么桌面端vue3组件库)
  • 弹窗组件:v3layer(基于vue3自定义弹窗组件)
  • 美化滚动条:v3scroll(基于vue3自定义滚动条组件)
  • 字体图标:阿里iconfont图标

项目结构

img

img

img

img

img

img

img

img

img

img

img

img

img

img

vue3.x全局模态框组件

v3layer基于vue3开发的仿layer.js自定义弹出层组件。应用于整个项目弹窗功能。

img

之前有过一篇详细介绍,感兴趣的可以去看看。

vue3自定义组件系列:vue3.0全局弹窗组件|对话框组件

vue3.x全局滚动条组件

v3scroll基于vue3开发的仿el-scrollbar自定义美化滚动条组件。在各个模块页面均有使用。

img

vue3自定义组件系列:vue3.0自定义pc端模拟滚动条组件

vue3入口页配置

在main.js中引入一些公共组件/样式、路由地址及vuex配置。

/**  
 * Vue3.0入口配置  
 */  

import { createApp } from 'vue'  
import App from './App.vue'  

// 引入vuex和地址路由  
import store from './store'  
import router from './router'  

// 引入公共组件  
import Plugins from './plugins'  

/* 引入公共样式 */  
import '@assets/fonts/iconfont.css'  
import '@assets/css/reset.css'  
import '@assets/css/layout.css'  

const app = createApp(App)  

app.use(store)  
app.use(router)  
app.use(Plugins)  

app.mount('#app')

vue3实现60s倒计时+表单验证

/**  
 * @Desc     vue3表单验证  
 * @Time     andy by 2021-01  
 * @About    Q:282310962  wx:xy190310  
 */  
<script>  
import { reactive, toRefs, inject, getCurrentInstance } from 'vue'  
export default {  
    components: {},  
    setup() {  
        const { ctx } = getCurrentInstance()  
        const v3layer = inject('v3layer')  
        const utils = inject('utils')  

        const formObj = reactive({})  
        const data = reactive({  
            vcodeText: '获取验证码',  
            disabled: false,  
            time: 0,  
        })  

        const VTips = (content) => {  
            v3layer({  
                content: content, layerStyle: 'background:#ff5151;color:#fff;', time: 2  
            })  
        }  

        const handleSubmit = () => {  
            if(!formObj.tel){  
                VTips('手机号不能为空!')  
            }else if(!utils.checkTel(formObj.tel)){  
                VTips('手机号格式不正确!')  
            }else if(!formObj.pwd){  
                VTips('密码不能为空!')  
            }else if(!formObj.vcode){  
                VTips('验证码不能为空!')  
            }else{  
                ctx.$store.commit('SET_TOKEN', utils.setToken());  
                ctx.$store.commit('SET_USER', formObj.tel);  

                // ...  
            }  
        }  

        // 60s倒计时  
        const handleVcode = () => {  
            if(!formObj.tel) {  
                VTips('手机号不能为空!')  
            }else if(!utils.checkTel(formObj.tel)) {  
                VTips('手机号格式不正确!')  
            }else {  
                data.time = 60  
                data.disabled = true  
                countDown()  
            }  
        }  
        const countDown = () => {  
            if(data.time > 0) {  
                data.vcodeText = '获取验证码('+ data.time +')'  
                data.time--  
                setTimeout(countDown, 1000)  
            }else{  
                data.vcodeText = '获取验证码'  
                data.time = 0  
                data.disabled = false  
            }  
        }  

        return {  
            formObj,  
            ...toRefs(data),  
            handleSubmit,  
            handleVcode  
        }  
    }  
}  
</script>

毛玻璃效果

大家看到项目中的背景是被模糊虚化的,使用了svg filter来实现。

<!-- //模糊化效果 -->  
<div class="vui__bgblur">  
  <svg width="100%" height="100%" class="blur-svg" viewBox="0 0 1920 875" preserveAspectRatio="none">  
    <filter id="blur_mkvvpnf"><feGaussianBlur in="SourceGraphic" stdDeviation="50"></feGaussianBlur></filter>  
    <image :xlink:href="store.state.skin" x="0" y="0" width="100%" height="100%" externalResourcesRequired="true" xmlns:xlink="http://www.w3.org/1999/xlink" style="filter:url(#blur_mkvvpnf)" preserveAspectRatio="none"></image>  
  </svg>  
  <div class="blur-cover"></div>  
</div>

图片/视频预览

图片预览使用element-plus中的image组件就能轻易实现。

<el-image class="img__pic"   
    :src="item.imgsrc"  
    :preview-src-list="[item.imgsrc]"  
    hide-on-click-modal  
/>

视频弹窗预览是使用v3layer组件实现。

<!-- 视频播放器 -->  
<v3-layer v-model="isShowVideoPlayer"  
    title="<i class='iconfont icon-bofang'></i> 视频预览"  
    layerStyle="background:#f9f9f9"  
    opacity=".2"  
    :area="['550px', '450px']"  
    xclose  
    resize  
    :maximize="true"  
>  
    <video class="vplayer" ref="playerRef" autoplay preload="auto" controls  
        :src="videoList.videosrc"  
        :poster="videoList.imgsrc"  
        x5-video-player-fullscreen="true"  
        webkit-playsinline="true"  
        x-webkit-airplay="true"  
        playsinline="true"  
        x5-playsinline  
    />  
</v3-layer>

网址链接预览

通过v3layer iframe弹窗来实现预览网址链接。

const handleMsgClicked = (e) => {  
    let target = e.target  
    // 链接  
    if(target.tagName === 'A') {  
        e.preventDefault()  
        // console.log('触发点击链接事件!')  

        v3layer({  
            type: 'iframe',  
            title: '<i class="iconfont icon-link"></i> 网址预览',  
            content: target.href,  
            opacity: .2,  
            area: ['860px', '600px'],  
            xclose: true,  
            resize: true,  
            maximize: true  
        })  
    }  
    // 图片  
    if (target.tagName === 'IMG' && target.classList.contains('img-view')) {  
        // ...  
    }  
}

发红包效果

发红包弹窗也是使用v3layer来实现的。通过引入外部页面,自定义插槽引入即可。

import SendRedPacket from './redPacket.vue'  

<!-- ……发红包模板 -->  
<v3-layer v-model="isShowSendRedPacketLayer"  
    layerStyle="background:#fff8f4"  
    opacity=".2"  
    :area="['400px', '480px']"  
    xclose  
    xcolor="#ffdccb"  
    drag='.ntDrag__head'  
>  
    <SendRedPacket />  
</v3-layer>

好了,以上就是基于vue3开发网页端聊天实例的一些分享,希望对大家有些帮助哈!

nuxt.js+vue仿微信app端聊天实例

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

继续阅读 »

项目简介

一周前有给大家分享一个vue3版手机端聊天实战项目。今天给大家带来的是基于vue3.x+饿了么vue3组件库开发的pc桌面端仿制微信+QQ界面聊天|朋友圈实例。

vue3.0仿微信app界面聊天室

img

vue3-webchat 聊天实例支持发送图文消息、预览视频/图片、网址查看、拖拽发送图片、红包/朋友圈等功能。

QQ皮肤效果
img

微信皮肤效果
img

使用技术

  • 编辑器:VScode
  • MVVM框架:Vue3.0.5
  • 状态管理:Vuex4.x
  • 页面路由:Vue-Router@4
  • UI组件库:element-plus (饿了么桌面端vue3组件库)
  • 弹窗组件:v3layer(基于vue3自定义弹窗组件)
  • 美化滚动条:v3scroll(基于vue3自定义滚动条组件)
  • 字体图标:阿里iconfont图标

项目结构

img

img

img

img

img

img

img

img

img

img

img

img

img

img

vue3.x全局模态框组件

v3layer基于vue3开发的仿layer.js自定义弹出层组件。应用于整个项目弹窗功能。

img

之前有过一篇详细介绍,感兴趣的可以去看看。

vue3自定义组件系列:vue3.0全局弹窗组件|对话框组件

vue3.x全局滚动条组件

v3scroll基于vue3开发的仿el-scrollbar自定义美化滚动条组件。在各个模块页面均有使用。

img

vue3自定义组件系列:vue3.0自定义pc端模拟滚动条组件

vue3入口页配置

在main.js中引入一些公共组件/样式、路由地址及vuex配置。

/**  
 * Vue3.0入口配置  
 */  

import { createApp } from 'vue'  
import App from './App.vue'  

// 引入vuex和地址路由  
import store from './store'  
import router from './router'  

// 引入公共组件  
import Plugins from './plugins'  

/* 引入公共样式 */  
import '@assets/fonts/iconfont.css'  
import '@assets/css/reset.css'  
import '@assets/css/layout.css'  

const app = createApp(App)  

app.use(store)  
app.use(router)  
app.use(Plugins)  

app.mount('#app')

vue3实现60s倒计时+表单验证

/**  
 * @Desc     vue3表单验证  
 * @Time     andy by 2021-01  
 * @About    Q:282310962  wx:xy190310  
 */  
<script>  
import { reactive, toRefs, inject, getCurrentInstance } from 'vue'  
export default {  
    components: {},  
    setup() {  
        const { ctx } = getCurrentInstance()  
        const v3layer = inject('v3layer')  
        const utils = inject('utils')  

        const formObj = reactive({})  
        const data = reactive({  
            vcodeText: '获取验证码',  
            disabled: false,  
            time: 0,  
        })  

        const VTips = (content) => {  
            v3layer({  
                content: content, layerStyle: 'background:#ff5151;color:#fff;', time: 2  
            })  
        }  

        const handleSubmit = () => {  
            if(!formObj.tel){  
                VTips('手机号不能为空!')  
            }else if(!utils.checkTel(formObj.tel)){  
                VTips('手机号格式不正确!')  
            }else if(!formObj.pwd){  
                VTips('密码不能为空!')  
            }else if(!formObj.vcode){  
                VTips('验证码不能为空!')  
            }else{  
                ctx.$store.commit('SET_TOKEN', utils.setToken());  
                ctx.$store.commit('SET_USER', formObj.tel);  

                // ...  
            }  
        }  

        // 60s倒计时  
        const handleVcode = () => {  
            if(!formObj.tel) {  
                VTips('手机号不能为空!')  
            }else if(!utils.checkTel(formObj.tel)) {  
                VTips('手机号格式不正确!')  
            }else {  
                data.time = 60  
                data.disabled = true  
                countDown()  
            }  
        }  
        const countDown = () => {  
            if(data.time > 0) {  
                data.vcodeText = '获取验证码('+ data.time +')'  
                data.time--  
                setTimeout(countDown, 1000)  
            }else{  
                data.vcodeText = '获取验证码'  
                data.time = 0  
                data.disabled = false  
            }  
        }  

        return {  
            formObj,  
            ...toRefs(data),  
            handleSubmit,  
            handleVcode  
        }  
    }  
}  
</script>

毛玻璃效果

大家看到项目中的背景是被模糊虚化的,使用了svg filter来实现。

<!-- //模糊化效果 -->  
<div class="vui__bgblur">  
  <svg width="100%" height="100%" class="blur-svg" viewBox="0 0 1920 875" preserveAspectRatio="none">  
    <filter id="blur_mkvvpnf"><feGaussianBlur in="SourceGraphic" stdDeviation="50"></feGaussianBlur></filter>  
    <image :xlink:href="store.state.skin" x="0" y="0" width="100%" height="100%" externalResourcesRequired="true" xmlns:xlink="http://www.w3.org/1999/xlink" style="filter:url(#blur_mkvvpnf)" preserveAspectRatio="none"></image>  
  </svg>  
  <div class="blur-cover"></div>  
</div>

图片/视频预览

图片预览使用element-plus中的image组件就能轻易实现。

<el-image class="img__pic"   
    :src="item.imgsrc"  
    :preview-src-list="[item.imgsrc]"  
    hide-on-click-modal  
/>

视频弹窗预览是使用v3layer组件实现。

<!-- 视频播放器 -->  
<v3-layer v-model="isShowVideoPlayer"  
    title="<i class='iconfont icon-bofang'></i> 视频预览"  
    layerStyle="background:#f9f9f9"  
    opacity=".2"  
    :area="['550px', '450px']"  
    xclose  
    resize  
    :maximize="true"  
>  
    <video class="vplayer" ref="playerRef" autoplay preload="auto" controls  
        :src="videoList.videosrc"  
        :poster="videoList.imgsrc"  
        x5-video-player-fullscreen="true"  
        webkit-playsinline="true"  
        x-webkit-airplay="true"  
        playsinline="true"  
        x5-playsinline  
    />  
</v3-layer>

网址链接预览

通过v3layer iframe弹窗来实现预览网址链接。

const handleMsgClicked = (e) => {  
    let target = e.target  
    // 链接  
    if(target.tagName === 'A') {  
        e.preventDefault()  
        // console.log('触发点击链接事件!')  

        v3layer({  
            type: 'iframe',  
            title: '<i class="iconfont icon-link"></i> 网址预览',  
            content: target.href,  
            opacity: .2,  
            area: ['860px', '600px'],  
            xclose: true,  
            resize: true,  
            maximize: true  
        })  
    }  
    // 图片  
    if (target.tagName === 'IMG' && target.classList.contains('img-view')) {  
        // ...  
    }  
}

发红包效果

发红包弹窗也是使用v3layer来实现的。通过引入外部页面,自定义插槽引入即可。

import SendRedPacket from './redPacket.vue'  

<!-- ……发红包模板 -->  
<v3-layer v-model="isShowSendRedPacketLayer"  
    layerStyle="background:#fff8f4"  
    opacity=".2"  
    :area="['400px', '480px']"  
    xclose  
    xcolor="#ffdccb"  
    drag='.ntDrag__head'  
>  
    <SendRedPacket />  
</v3-layer>

好了,以上就是基于vue3开发网页端聊天实例的一些分享,希望对大家有些帮助哈!

nuxt.js+vue仿微信app端聊天实例

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

收起阅读 »

个人发卡网源码|个人发卡网系统带搭建平台方法

源码分享

  个人发卡网源码系统是一个即时服务软件系统(SaaS)的解决方案,它使工程团队能够在云中实现和优化CI和CD,并帮助小型和成长中的团队开发从简单的web应用程序到现代微服务架构的一切,以实现快速、安全和频繁的代码交付。
  
  个人发卡网源码系统演示及下载搭建方法:点击获取
  

  个人发卡网源码系统特点:
  
  1、自动发卡一键掌控
  
  您是希望立即为您设置所有内容,还是要自定义您的环境和工作流?CloudBees CodeShip允许开发人员选择最适合他们的路径,以最大限度地提高生产力,并让团队随着时间的推移而发展。
  
  2、在几分钟内完全工作
  
  使用CloudBees CodeShip的交钥匙环境和简单的UI,您可以在不到五分钟的时间内完成构建和部署。从那里,您可以发展到更复杂的工作流,并随着项目的增长而配置为代码。
  
  3、与所有事物集成
  
  从部署到通知到代码覆盖,再到安全扫描和内部scm,CloudBees CodeShip允许您与任何工具、服务或云集成,以实现组织的完美工作流。
  
  4、保证速度和可靠性
  
  您需要您的构建运行速度快,易于优化和调试,并且始终可用。我们构建了具有弹性和高性能的基础设施,并构建了CloudBees代码,使闪电般快速的构建速度易于实现。
  
  5、由于专用的单租户AWS实例,性能和安全性都得到了保证
  
  选择我们为您提供的AWS实例的大小、CPU和内存。由于您的代码只运行在一个实例上,而您没有与其他人共享实例,因此我们可以保证高安全性,并确保您不会受到其他团队运行的CPU过多构建的影响。
  

  个人发卡网源码系统一种新的支付形式,C开发人员可以编写它,让您可以做两件事:
  
  一是检索汇编对象,它表示正在编译的所有用户代码。这个对象可以被检查,您可以编写与正在编译的代码的语法和语义模型一起工作的代码,就像今天的分析器一样。
  
  二是生成可添加到汇编对象。换句话说,您可以在编译代码时提供额外的源代码作为编译的输入。
  
  将这两个因素结合起来,使源生成器变得如此有用。您可以使用编译器在编译期间构建的所有丰富的元数据检查用户代码,然后将C代码重新发送到基于所分析数据的同一编译中!如果您熟悉Roslyn分析器,那么可以将源代码生成器看作可以发出C源代码的分析器。
  
  个人发卡网源码系统是一个.NET标准2.0程序集,它与任何分析仪. 它在可以加载和运行.NET标准组件的环境中可用。
  
  现在您已经知道了什么是源生成器,让我们来看看它们可以改进的一些场景。
  
  使用个人发卡网源码系统可以做的事情远不止是这样简单:
  
  自动实现带有附加属性的类的接口,例如INotifyProperty已更改
  
  根据从中检查的数据生成设置文件SourceGeneratorContext
  
  将类中的值序列化为JSON字符串等。
  
  另外,我们还有一个GitHub上提供的一组示例你可以自己试试。
  

  如前所述,我们正致力于在实际应用中更好地编写和使用个人发卡网源码系统,例如添加模板、允许无缝的智能感知和导航、调试以及提高生成源文件时visualstudio的响应能力和性能。

继续阅读 »

  个人发卡网源码系统是一个即时服务软件系统(SaaS)的解决方案,它使工程团队能够在云中实现和优化CI和CD,并帮助小型和成长中的团队开发从简单的web应用程序到现代微服务架构的一切,以实现快速、安全和频繁的代码交付。
  
  个人发卡网源码系统演示及下载搭建方法:点击获取
  

  个人发卡网源码系统特点:
  
  1、自动发卡一键掌控
  
  您是希望立即为您设置所有内容,还是要自定义您的环境和工作流?CloudBees CodeShip允许开发人员选择最适合他们的路径,以最大限度地提高生产力,并让团队随着时间的推移而发展。
  
  2、在几分钟内完全工作
  
  使用CloudBees CodeShip的交钥匙环境和简单的UI,您可以在不到五分钟的时间内完成构建和部署。从那里,您可以发展到更复杂的工作流,并随着项目的增长而配置为代码。
  
  3、与所有事物集成
  
  从部署到通知到代码覆盖,再到安全扫描和内部scm,CloudBees CodeShip允许您与任何工具、服务或云集成,以实现组织的完美工作流。
  
  4、保证速度和可靠性
  
  您需要您的构建运行速度快,易于优化和调试,并且始终可用。我们构建了具有弹性和高性能的基础设施,并构建了CloudBees代码,使闪电般快速的构建速度易于实现。
  
  5、由于专用的单租户AWS实例,性能和安全性都得到了保证
  
  选择我们为您提供的AWS实例的大小、CPU和内存。由于您的代码只运行在一个实例上,而您没有与其他人共享实例,因此我们可以保证高安全性,并确保您不会受到其他团队运行的CPU过多构建的影响。
  

  个人发卡网源码系统一种新的支付形式,C开发人员可以编写它,让您可以做两件事:
  
  一是检索汇编对象,它表示正在编译的所有用户代码。这个对象可以被检查,您可以编写与正在编译的代码的语法和语义模型一起工作的代码,就像今天的分析器一样。
  
  二是生成可添加到汇编对象。换句话说,您可以在编译代码时提供额外的源代码作为编译的输入。
  
  将这两个因素结合起来,使源生成器变得如此有用。您可以使用编译器在编译期间构建的所有丰富的元数据检查用户代码,然后将C代码重新发送到基于所分析数据的同一编译中!如果您熟悉Roslyn分析器,那么可以将源代码生成器看作可以发出C源代码的分析器。
  
  个人发卡网源码系统是一个.NET标准2.0程序集,它与任何分析仪. 它在可以加载和运行.NET标准组件的环境中可用。
  
  现在您已经知道了什么是源生成器,让我们来看看它们可以改进的一些场景。
  
  使用个人发卡网源码系统可以做的事情远不止是这样简单:
  
  自动实现带有附加属性的类的接口,例如INotifyProperty已更改
  
  根据从中检查的数据生成设置文件SourceGeneratorContext
  
  将类中的值序列化为JSON字符串等。
  
  另外,我们还有一个GitHub上提供的一组示例你可以自己试试。
  

  如前所述,我们正致力于在实际应用中更好地编写和使用个人发卡网源码系统,例如添加模板、允许无缝的智能感知和导航、调试以及提高生成源文件时visualstudio的响应能力和性能。

收起阅读 »

安卓 app 视频闪退问题

第一个问题: 视频图片列表页分页加载,只要有一个视频预加载报错,安卓端app就会闪退,ios正常
第二个问题:onPageScroll 用户滚动时播放当前的视频,视频过多安卓端app就会闪退,ios正常
onLoad(options) {
//创建视频上下文
this.videoContent = uni.createVideoContext
},
onPageScroll(e){
const that = this
if(that.tabId=="dynamic" && app.globalData.platformObj.platform=='ios'){
if(that.playId){
that.videoContent(that.playId).pause(); //暂停上一次播放的视频
that.playId = ''
}
clearTimeout(that.debounce)
that.debounce = setTimeout(()=>{
that.dynListData.forEach(item=>{
if(item.type==2){
let scrTop = parseInt(e.scrollTop),top = parseInt(item.top) + parseInt(item.height);
if(scrTop<top && scrTop+300>top){
console.log('播放用户当前滑动的视频')
let currentId = 'video' + item.id;// 获取当前视频id
that.playId = currentId
that.videoContent(currentId).play(); //播放当前视频
// return
}
}
})
}, 500)
}
}

继续阅读 »

第一个问题: 视频图片列表页分页加载,只要有一个视频预加载报错,安卓端app就会闪退,ios正常
第二个问题:onPageScroll 用户滚动时播放当前的视频,视频过多安卓端app就会闪退,ios正常
onLoad(options) {
//创建视频上下文
this.videoContent = uni.createVideoContext
},
onPageScroll(e){
const that = this
if(that.tabId=="dynamic" && app.globalData.platformObj.platform=='ios'){
if(that.playId){
that.videoContent(that.playId).pause(); //暂停上一次播放的视频
that.playId = ''
}
clearTimeout(that.debounce)
that.debounce = setTimeout(()=>{
that.dynListData.forEach(item=>{
if(item.type==2){
let scrTop = parseInt(e.scrollTop),top = parseInt(item.top) + parseInt(item.height);
if(scrTop<top && scrTop+300>top){
console.log('播放用户当前滑动的视频')
let currentId = 'video' + item.id;// 获取当前视频id
that.playId = currentId
that.videoContent(currentId).play(); //播放当前视频
// return
}
}
})
}, 500)
}
}

收起阅读 »