精华内容
下载资源
问答
  • easyui前段交互框架

    2016-10-31 17:15:38
    easyui 前段交互框架 选项卡
  • Android网络交互框架

    2014-06-19 15:31:34
    自己实现的Android联网交互框架,完全解耦,使用方便。
  • VTK 交互框架

    2018-12-02 16:50:56
    他人专栏 ...VTK交互框架 VTK相机 SetClippingRange 0.01 - 1000 景深范围,不在此范围的都不能被显示,在SetClippingRange之前不要调用GetClippingRange,不然相机的景深就已经乱了。 《vtk ...

    他人专栏

    VTK 三维数据渲染进阶 https://blog.csdn.net/shenziheng1/column/info/25449

     

    VTK交互框架

    VTK相机

    SetClippingRange 0.01 - 1000 景深范围,不在此范围的都不能被显示,在SetClippingRange之前不要调用GetClippingRange,不然相机的景深就已经乱了。

    《vtk user‘s Guide》4.4 Controlling The Camera里有常用的几个其他函数的介绍

     

     

     

    展开全文
  • 作者从业于人工智能语音公司多年,简单聊聊设备端语音交互框架设计。 二、设计 一般语音交互类产品中会涉及到语音唤醒、语音识别、语义识别、对话理解、语音合成等相关技术,对于这些技术细节博主不是这方面的专业...

    一、目的

    随着人工智能技术的不断发展,语音识别、图像识别、人机交互这几年越来越成为热门。作者从业于人工智能语音公司多年,简单聊聊设备端语音交互框架设计。

    二、设计

    一般语音交互类产品中会涉及到语音唤醒、语音识别、语义识别、对话理解、语音合成等相关技术,对于这些技术细节博主不是这方面的专业人员了解的不多,但这并不影响应用开发人员去设计一个语音交互框架。

    一个完整的语音交互类产品一般分为以下模块,如图:

    语音交互框架

    其中虚线方框中的各项功能SDK一般由特定的语音厂商提供,在语音行业中比较有名包括思必驰、阿里、百度。椭圆虚线框中的各个模块根据产品的业务需要自行删减设计;其中特别需要关注是播放管理,这个我会在后期的博文中单独拆分说明。

    录音模块即设备录音,这个一般由硬件厂商或者驱动开发人员适配特定的codec对外统一成alsa接口或者其他特定的录音接口。

    信号处理一般是指回声消除、消噪、增强、beamforming等技术,最近比较流行的即麦克风阵列技术,包括线性阵列、环形阵列。

    唤醒即语音唤醒,即设备时刻监听用户说话,当用户说出特定的词时,设备被唤醒,例如天猫精灵、小度小度等。

    语音端点检测即VAD语音算法从录音中判断出话音的起点与终点,截取用户有效语音内容,交由后续语音识别模块使用。

    本地识别即语音转文本并且是在设备端处理,这个一般对设备的性能(存储、算力)有一定的要求。

    云端识别一般是将语音数据发送给语音云,由云端进行识别后反馈给设备端。一般情况下语音数据都是会进行压缩处理,比较流行的有speex ogg等算法。现在市面上各个大厂都有自己的一套语音云服务,例如思必驰DUI平台。

     

    关于如何将前端信号处理、唤醒、语音断点检测、本地识别、云端识别设计成一个语音SDK,后续会在其他博文中加以说明,敬请期待。

     

    展开全文
  • IOS 客户端与服务端之间数据交互框架 和 文件操作类库
  • JsBridge交互框架的使用

    千次阅读 2019-01-07 16:53:21
    JsBridge交互框架的使用 现在很多App都采用了混合开发,对于展示性强的界面,可以用H5去实现;功能性强的的可以在用native实现。在混合开发中可以说native和JS进行交互肯定是要涉及到的,当然如果你们项目不是混合...

                                       JsBridge交互框架的使用

    现在很多App都采用了混合开发,对于展示性强的界面,可以用H5去实现;功能性强的的可以在用native实现。在混合开发中可以说native和JS进行交互肯定是要涉及到的,当然如果你们项目不是混合开发,某些地方只是需要展示一下H5界面即可,也就涉及不到这块。说到交互,虽然Android系统为我们提供的@JavascriptInterface这种交互方式,但是由于兼容性与安全性的问题,我们基本不再使用。今天所说的JsBridge就是安全性和兼容性比较好的一种交互方式,在混合式的开发中非常受欢迎。

         实现native层对JS的单向通信,只需要调用方法Webview.loadUrl("JavaScript:function()")即可。那如何实现H5层对native层的通信呢? JS层调用native层不是通过某一个方法就能直接调用的,他是一层一层调用的。为了方便理解,首先得提一下native层的WebChromClient这个类,这个类有三个方法分别是onJsAlert,onJsConfirm,onJsPrompt另外还得提一下JS层的window这个对象也有三个方法window.alertwindow.confirmwindow.prompt,当JS层调用windown对象中的某个方法的时候,相应的就会触发WebChromClient对象中对应的方法。说到这里你可能应该猜到了,我们就是通过这种响应机制来实现JS层对native层的通信。这三个方法用哪个呢?一般来说,我们是不会使用onJsAlert的,为什么呢?因为js中alert使用的频率还是非常高的,一旦我们占用了这个通道,alert的正常使用就会受到影响,而confirmprompt的使用频率相对alert来说,则更低一点。那么到底是选择confirm还是prompt呢,其实confirm的使用频率也是不低的,比如你点一个链接下载一个文件,这时候如果需要弹出一个提示进行确认,点击确认就会下载,点取消便不会下载,类似这种场景还是很多的,因此不能占用confirm。而prompt则不一样,在Android中,几乎不会使用到这个方法,就是用,也会进行自定义,所以我们完全可以使用这个方法。说到这,JS层对native层的通信的核心连接点已经说完了。你可能会疑惑,说好的JsBridge呢?毛都没看见,交互就结束了?千万别急啊,话说JSBridge就是一个协议,类似于http这种协议的东西。简单点说,这个协议就是native层和JS层约定好的一个协议,你JS层传给我的信息得按这个协议来进行包装,层层传递到native层。native层接收到这个信息的时候,也是根据这个协议进行解析获取我们需要的信息,比如你调我的哪个类,哪个方等等.这个后面会细说(jsbridge://className:port/methodName?jsonObj)

    依赖:compile 'com.msj.javajsbridge:javajsbridge:1.0.4'
    
    

       上面说的,大家只要知道JS调用native层的调用机制就行了。JS调用下面直接上代码分析流程,每次只要按这个流程一步一步的走,实现起来也不是什么难事。

    1.从JS层看起(下面的代码)。JS交互时候,JS层首先调用的是call(obj,method,params,callback)这个方法。(obj:调用的类名。method:调用哪个方法。params:参数。 callback:回调处理native返回给JS的处理结果。 port:随机生成的一个值,它是与callback对应的)。通过getUri将信息按协议封装成uri,在调用window.prompt(uri,“”)方法,这时候native层就会相应的调用onJsPrompt方法,并且会接收JS层传来的uri信息。onFinish(port,jsonObj)方法回调的时候用,暂时不说,只要注意下有这么个东西就行。
    (function(win) {
        var hasOwnProperty = Object.prototype.hasOwnProperty;
        var JSBridge = win.JSBridge || (win.JSBridge = {});
        var JSBRIDGE_PROTOCOL = 'JSBridge';
        var Inner = {
            callbacks: {},
            call: function(obj, method, params, callback) {
                console.log(obj + " " + method + " " + params + " " + callback);
                var port = Util.getPort();
                console.log(port);
                this.callbacks[port] = callback;
                var uri = Util.getUri(obj, method, params, port);
                console.log(uri);
                window.prompt(uri, "");
            },
            onFinish: function(port, jsonObj) {
                var callback = this.callbacks[port];
                callback && callback(jsonObj);
                delete this.callbacks[port];
            },
        };
        var Util = {
            getPort: function() {
                return Math.floor(Math.random() * (1 << 30));
            },
            getUri: function(obj, method, params, port) {
                params = this.getParam(params);
                var uri = JSBRIDGE_PROTOCOL + '://' + obj + ':' + port + '/' + method + '?' + params;
                return uri;
            },
            getParam: function(obj) {
                if (obj && typeof obj === 'object') {
                    return JSON.stringify(obj);
                } else {
                    return obj || '';
                }
            }
        };
        for (var key in Inner) {
            if (!hasOwnProperty.call(JSBridge, key)) {
                JSBridge[key] = Inner[key];
            }
        }
    })(window);

     

    2.这里我们先自定义一个WebView类:主要用来进行一些设置。        第一,设置我们自定义的WebchromClient类。这里面为了扩展性,给自定义的WebchromClient加了个接口,方便在Activity或者Fragment中进行处理。     第二, register(“bridge”,CommonBridgeImp)反射获取native层CommonBridgeImp类中暴露给JS层的所有方法,并且存到一个HashMap<bridge,HashMap<方法名,Method>>集合中。

     

     

    @Keep
    public class CommonWebView extends WebView {
    
        /**
         * context of the webview page.
         */
        Context context;
        /**
         * the webview that show the page.
         */
        WebView webView;
        /**
         * activity of the webview.
         */
        Activity activity;
        /**
         * the root url of the website. url include index.html.
         */
        String rootUrl = "";
    
        /**
         * loading dialog.
         */
        LoadingDialog dialog;
    
        /**
         * ICommonActivityImp
         */
        ICommonActivityImp commonActivityImp;
    
        @Keep
        public CommonWebView(Context context,
                             String rootUrl,
                             ICommonActivityImp commonActivityImp) {
            super(context);
            this.context = context;
            this.rootUrl = rootUrl;
            this.activity = (Activity) context;
            this.commonActivityImp = commonActivityImp;
    
        }
    
    
        /**
         * init webview settings.
         */
        public void initWebView(final LoadingDialog dialog) {
            webView = this;
            this.dialog = dialog;
            WebSettings settings = webView.getSettings();
            settings.setJavaScriptEnabled(true);
            settings.setGeolocationEnabled(true);//webview华为7.0定位
            webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);//解决echats插件图表无法截图问题
            settings.setDomStorageEnabled(true);//设置允许本地存储
            settings.setAppCacheEnabled(true);
            settings.setAllowFileAccess(true);// 设置允许访问文件数据
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                settings.setMixedContentMode(0);
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                settings.setMediaPlaybackRequiresUserGesture(true);
            }
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
                settings.setAllowFileAccessFromFileURLs(true);
                settings.setAllowUniversalAccessFromFileURLs(true);
            }
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
                webView.getSettings().setAppCacheMaxSize(1024 * 1024 * 8);
            }
            settings.setAppCachePath(context.getCacheDir().getAbsolutePath());
            settings.setCacheMode(WebSettings.LOAD_DEFAULT);
            CommonJSBridge.register("bridge", CommonBridgeImp.class);
            webView.setWebChromeClient(new CommonJSBridgeWebChromeClient(activity, commonActivityImp));
            webView.setWebViewClient(new WebViewClient() {
    
                @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    super.onPageStarted(view, url, favicon);
                    if (dialog != null && !dialog.isShowing()) {
                        dialog.show();
                    }
                }
    
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    view.loadUrl(url);
                    return true;
                }
    
                @Override
                public void onPageFinished(WebView view, String url) {
                    super.onPageFinished(view, url);
                    if (dialog != null && dialog.isShowing()) {
                        dialog.dismiss();
                    }
                }
    
    
                public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                    handler.proceed();
                }
            });
           
        }
    

     

     

     

    3.自定义WebChromClient这个类,通过onJsPrompt方法接收JS传来的uri,即是这里的message。onJsPrompt方法会调用result.confirm()==>CommonJsBridge.callJava();这里就是将uri传入到CommonJsBridge类中了,进行下一步的解析处理,并进行native层的方法调用。

     

    public class CommonJSBridgeWebChromeClient extends WebChromeClient {
        Activity mActivity;
        ICommonActivityImp commonActivityImp;
    
        public CommonJSBridgeWebChromeClient(Activity activity, ICommonActivityImp commonActivityImp) {
           this. mActivity = activity;
           this. commonActivityImp=commonActivityImp;
        }
    
        /**
         * 核心方法,整个原生和h5交互的方式都是通过获取h5页面调用原生时通过osJsPrompt方法的传值进行交互
         * @param view
         * @param url
         * @param message (uri)
         * @param defaultValue
         * @param result
         * @return
         */
        @Override
        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
            result.confirm(CommonJSBridge.callJava(view, message,commonActivityImp));
            return true;
        }
    
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            return super.onJsAlert(view, url, message, result);
        }
        
    
        @Override
        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
            return super.onJsConfirm(view, url, message, result);
        }
    
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            mActivity.setProgress(newProgress);
            super.onProgressChanged(view, newProgress);
        }
    }

     

    我写的接口(仅供参考,根据自己业务需求定):

     

    
    public interface ICommonImp{
    }
    
    public interface ICommonActivityImp extend ICommonImp {
        void jumpNextBanner(WebView webView, String type, String value, Callback callback);
    }

     

     

     

       4.上面调用的callJava()方法,就在CommonJsBridge这个类里面,里面是根据JsBridge协议用来解析uri,可以看看下面的注释。获取将要调用的类名,方法名,以及Port  ,然后去集合中找到此类名的此方法。 一般的,我们将这些方法统一写到一个类中,通过反射获取这个类中的所有方法并保存到HashMap集合exposeMethods中。

     

    public class CommonJSBridge {
        /**
         * 此方法通过WebView的onJsPrompt方法调用,为js调用原生的方法,根据方法名从methodMap拿到方法,反射调用,并将参数传进去
         *
         * @param webView
         * @param uriString 此参数为h5页面调用原生时的uri,格式如:(JSBridge://className:port/methodName?jsonObj),格式与JSBridge.js文件中定义一致
         * @return
         * @see CommonJSBridgeWebChromeClient# onJsPrompt(WebView, String, String, String, JsPromptResult)
         */
        public static String callJava(WebView webView, String uriString, ICommonImp baseWebImp) {
            String methodName = "";//暴露给js的类中的方法
            String className = "";//暴露给js的类
            String param = "{}";//json格式的参数,可是字符串,自己定义
            String port = "";//用于回调的端口号
            if (!TextUtils.isEmpty(uriString) && uriString.startsWith("JSBridge")) {
                Uri uri = Uri.parse(uriString);
                className = uri.getHost();
                param = uri.getQuery();
                port = uri.getPort() + "";
                String path = uri.getPath();
                if (!TextUtils.isEmpty(path)) {
                    methodName = path.replace("/", "");
                }
            }
    
            if (exposedMethods.containsKey(className)) {
                HashMap<String, Method> methodHashMap = exposedMethods.get(className);
    
                if (methodHashMap != null && methodHashMap.size() != 0 && methodHashMap.containsKey(methodName)) {
                    Method method = methodHashMap.get(methodName);
                    if (method != null) {
                        try {
                            method.invoke(null, webView, param, new Callback(webView, port), baseWebImp);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            return null;
        }
    
        /**
         * 暴露的类方法集合<类,此类的所有方法>
         */
        private static Map<String, HashMap<String, Method>> exposedMethods = new HashMap<>();
    
        /**
         * 注册暴露给js页面的类
         *
         * @param
         */
        public static void register(String exposedName, Class<? extends IBridge> clazz) {
            if (!exposedMethods.containsKey(exposedName)) {
                try {
                    exposedMethods.put(exposedName, getAllMethod(clazz));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 反射获取暴露给js的类中的方法
         * 暴露的方法必须是public static ,参数必须是(WebView,String,Callback),此处可修改,与BridgeImpl类中暴露的方法一致
         *
         * @param injectedCls
         * @return
         * @throws Exception
         */
        private static HashMap<String, Method> getAllMethod(Class injectedCls) throws Exception {
            HashMap<String, Method> mMethodsMap = new HashMap<>();
            Method[] methods = injectedCls.getDeclaredMethods();
            for (Method method : methods) {
                String name;
                if (method.getModifiers() != (Modifier.PUBLIC | Modifier.STATIC) || (name = method.getName()) == null) {
                    continue;
                }
                Class[] parameters = method.getParameterTypes();
                if (null != parameters && parameters.length == 4) {
                    if (parameters[0] == WebView.class && parameters[1] == String.class && parameters[2] == Callback.class && parameters[3] == ICommonActivityImp.class) {
                        mMethodsMap.put(name, method);
                    }
                }
            }
            return mMethodsMap;
        }
    }
    

     

     

     

    4.下面这个类CommonBridgeImp这个类是用来写暴露给JS层的所有的方法,注意方法必须用static  void 修饰,并且要实现空的接口IBridge主要是为了混淆的时候不会错。如果 需要Activity或者Fragment处理的调用上文自定义的ICommonBridgeImp这个接口回调。如果需要将数据返回给JS层或者再次调用JS层的方法,就通过Callback回调,将数据返回给JS层处理。

     

    /**
     * 暴露给JS调用的原生的方法
     */
    public class CommonBridgeImp implements IBridge {
        public static Handler handler = new Handler();
        public Context context;
        private CommonWebView commonWebView;
    
        private CommonBridgeImp(Context context, CommonWebView commonWebView) {
            this.context = context;
            this.commonWebView = commonWebView;
        }
    
        /**
         * 交互暴露的方法 fromJsFunction_test1
         * @param webView
         * @param param
         * @param callback
         */
        public static void fromJsFunction_test1(final WebView webView, String param, final Callback callback, final ICommonActivityImp commonActivityImp) {
            ArrayList<String> list = new ArrayList<>();
            list.add("type");
            list.add("value");
            String[] strArray = CommonUtil.getStrArray(param, list);
            final String type = strArray[0];
            final String value = strArray[1];
            handler.post(new Runnable() {
                @Override
                public void run() {
                    commonActivityImp.jumpNextBanner(webView, type, value, callback);
                }
            });
    
        }
    
    }

    5.这个CallBack是个啥?为什么哪个里面都有它?返回给JS层为什么得经过他呢?这个得从JS层说起,简单理一下就明白了。JS层调用native层的时候,会先在JS层产生一个port值,然后构造一个Callback回调保存起来,并且将port值封装到Uri里面传给native层,native层会将这个port值封装到自定义Callback中。等到native处理完数据之后,再回调JS层的onFinish方法,并将参数和port值一起传递回去。JS层在回调会根据这个port值找到对应的Callback做进一步的处理,并将这个Callback删除。

     

     

    package com.sgcc.cs.h5webviewpage.JSUtil;
    
    import android.os.Handler;
    import android.os.Looper;
    import android.webkit.WebView;
    
    
    import java.lang.ref.WeakReference;
    
    /**********************************************************************************
     * @Version : V4.0
     * @Date: 2017/2/23 09:42
     * @Description: 作用 回调,原生应用处理完成后,回调js中回调方法的类
     * *********************************************************************************
     * History:   update past records <Author>  <Date>   <Version>
     * <p>
     * 修改内容:涉及文件:
     * *********************************************************************************
     */
    public class Callback {
        private static Handler mHandler = new Handler(Looper.getMainLooper());
        /**
         * JSON串格式化参数
         */
        private static final String CALLBACK_JS_FORMAT_JSON = "javascript:JSBridge.onFinish('%s', %s);";
        /**
         * String串格式化参数,需要加引号,不然不会调用JSBridge.js中onFinish方法;
         * 原因:JavaScrip参数是String类型时,前后需要加引号
         */
        private static final String CALLBACK_JS_FORMAT_STRING = "javascript:JSBridge.onFinish('%s', \"%s\");";
        private String mPort;
        private WeakReference<WebView> mWebViewRef;
    
        public Callback(WebView view, String port) {
            mWebViewRef = new WeakReference<>(view);
            mPort = port;
        }
    
        /**
         * 若需要回调js中的回调方法,在相应的地方调用 Callback.apply(jsonObject)
         * @param jsonObject
         */
        public void apply(String jsonObject) {
            String resultStr;
            if (!"".equals(jsonObject)&&jsonObject.startsWith("{")){//判断是否为JSON,若不是,需要加引号
                resultStr = String.format(CALLBACK_JS_FORMAT_JSON, mPort, jsonObject);
            }else {
                resultStr = String.format(CALLBACK_JS_FORMAT_STRING, mPort, jsonObject);
            }
            final String execJs = resultStr;
            if (mWebViewRef != null && mWebViewRef.get() != null) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mWebViewRef.get().loadUrl(execJs);
                    }
                });
            }
        }
    }
    

    总结一下吧:

    一:method.invoke(null, webView, param, new Callback(webView, port), baseWebImp);的使用场景:

    1:如果你是打一个打的框架容器,用来加载H5页面的很多个业务模块可以把最后面的baseWebImp这个接口去掉,method.invoke(null, webView, param, new Callback(webView, port)。因为只需要接收JS层指令,并根据params中给的字段进行处理。如果需要将结果返回给Js层只需要调用callBack的apply即可。其实需要几个参数可以根据业务规范来定。个人还是喜欢按统一的规则来,舒心。

    2:如果只是在某个页面,或者某几个页面中嵌入一个网页,回调需要在activity或者Fragment中进行处理。则method.invoke(null, webView, param, new Callback(webView, port), baseWebImp);这样更灵活一点。 

    二:如果涉及到加载失败的默认图片这种情况,可以再WebViewChromClient  或者 WebViewClient 的错误方法中进行捕获并处理。

    三:如果是第一种情况,作为容器还会涉及到H5模块的下载,解压,存储等,还有跳转,返回键 等这些琐碎的但是又是不可忽略的功能补充。

    本人菜鸟一枚,如果有不好的,希望不吝指教,和谐交流,共同进步!

     

     

     

     

     

     

    展开全文
  • App主界面交互框架一览。提供专业的架构俗语
  • Siebel 8.1 IE高交互框架插件

    热门讨论 2012-04-09 14:46:52
    Siebel IE高交互框架插件,Siebel 版本为8.1,如果将此文件放在C:\Windows\Downloaded Program Files\目录下,并且执行REGSVR32 **.dll ,则不需要在进入Siebel时再安装此插件,主要原因为这个dll经常会烂掉。
  • 现代前端交互框架​ Web前端页面的开发避免不了与DOM的交互操作。前端框架的一次次变化,从提升效率的阶段,慢慢走向改善性能的阶段。直接DOM操作时代对于开发者来说,所有数据内容都可以通过DOM结构来组织和展示的...

    现代前端交互框架

    ​ Web前端页面的开发避免不了与DOM的交互操作。前端框架的一次次变化,从提升效率的阶段,慢慢走向改善性能的阶段。

    直接DOM操作时代

    对于开发者来说,所有数据内容都可以通过DOM结构来组织和展示的。数据的处理和操作的核心其实就是DOM的处理和操作。DOM API可以分为:节点查询型、节点创建型、节点修改型、节点关系型、节点属性型和内容加载型。

    类型 方法 jQuery方法
    节点查询型 getElementById、getElementByName、getElementsByClassName、getElementsByTagName、querySelector、querySelectorAll $(selector)、find()等
    节点创建型 createElement、createDocumentFragment、createTextNode、cloneNode $(selector)、clone()等
    节点修改型 appendChild、replaceChild、removeChild、insertBefore、innerHTML html()、replace()、remove()、append()、before()、after()等
    节点关系型 parentNode、previousSibling、childNodes parent()、siblings()、closest()、next()、children()等
    节点属性型 innerHTML、attributes、getAttribute、setAttribute、getComputedStyle attr()、data()、css()、hide()、show()、slideDown()、slideUp()、animate()等
    内容加载型 XMLHttpRequest、ActiveX ajax()、get()、post()等

    DOM的property和attribute区别:

    • property通常是指DOM元素对象的(固有)属性,例如style;
    • attribute是指HTML标签的文本标记属性,一般是可见的,如自定义的data-status属性;

    推荐使用createDocumentFragment来代替createElement创建节点内容

    因为createDocumentFragment可以将多个文档内容片段进行缓存,最后一次性插入DOM中,减少DOM操作次数,提高效率。

    AJAX跨域请求时默认不会带有浏览器Cookie信息

    需要在请求头部加上xhrFields:{withCredentials: true}才能将Cookie信息正常带到请求中发送给服务器。

    高效实用jQuery:

    • 尽可能使用id选择器进行DOM查询操作;
    • 缓存一切需要复用的jQuery DOM对象,使用find()子查询;
    • 不要滥用jQuery,尽可能使用原生代码代替;
    • 尽可能使用jQuery的静态方法;
    • 使用事件代理,不要直接使用元素的事件绑定;
    • 尽量使用新的jQuery版本;
    • 尽可能使用链式写法来提高编程效率和代码运行效率

    这里写图片描述

    随着AJAX技术盛行,SPA(Single Page Application,单页面应用)开始广泛被认可。其基本思路:将整个应用内容都在一个页面中实现并完全通过异步交互来根据用户操作加载不同的内容。在这期间,DOM操作和事件绑定将变得十分混乱,不便于管理,于是MV*框架运应而生。

    MV*交互模式

    前端MVC模式

    将页面DOM相关的内容抽象成数据模型视图事件控制函数(Model-View-Controller)三部分。

    • Model:用于存放请求的数据结果和数据对象;
    • View:用于页面DOM的更新与修改;
    • Controller:用于根据前端路由条件(例如不同的HASH路由)来调用不同Model给View渲染不同数据内容。
    const Router = {
        states: {},
        state(hash, conf) {
            this.states[hash] = conf;
        },
        fire(match) {
            let routerReg = new RegExp(match, 'g');
            for(let state in this.states) {
                if(routerReg.test(state)) {
                    this.states[state].controller();
                    break;
                }
            }
            return this;
        }
    };
    
    Router.state('#index', {
        controller:  () => {
            console.log('_loadIndex()');
        }
    });
    Router.state('#detail', {
        controller:  () => {
            console.log('_loadDetail()');
        }
    });
    // 监听路由变化
    window.addEventListener("hashchange", (event) => {
        // console.log(event.newURL, event.oldURL);
        Router.fire(location.hash);
    }, false);

    也可以使用HTML5的pushState来实现路由history.pushState(state, title, url)

    在MVC里,组件将自己的控制权给统一的控制对象来调用,大部分MVC框架通过事件监听或者观察者模式来实现的!

    <div id="A" onclick="A.event.change"></div>
    
    <script>    
        // 公共的Component基类
        let component = new Component();
        let A = component.extend({
          $el: document.getElementById('A'),
          model: {
            text: 'ViewA渲染完成'
          },
          view(data) {
            let tpl = '<span>{{text}}</span>';
            // 渲染模板
            let html = render(tpl, data);
            this.$el.innerHTML = html;
          },
          controller() {
            let self = this;
            // 将Model数据传入View中渲染
            self.view(self.model);
            // 监听hash变化
            window.addEventListener('hashChange', () => {/*...*/});
            // 监听事件
            self.event['change'] = function() {
              self.model.text = '...';
              self.view(self.model);
            }                                                          
          }
        })
    </script>

    需要注意:用户操作引起的DOM修改操作主要通过Controller来直接控制的,但是Controller只进行修改操作指令的分发,数据的渲染一般是在View层来完成!

    前端MVP模式

    MVP(Model-View-Presenter)和MVC区别在于:用户在进行DOM修改操作时将通过View上的行为触发,然后将修改通知给Presenter来完成后面的Model修改和其他View的更新(View和Presenter是双向的);而MVC模式下,用户的操作时直接通过Controller来控制的。

    <div id="A" onclick="A.event.change"></div>
    
    <script>    
        // 公共的Component基类
        let component = new Component();
        let A = component.extend({
          $el: document.getElementById('A'),
          model: {
            text: 'ViewA渲染完成'
          },
          view: '<input id="input" value="{{text}}"><span id="showText">{{text}}</span>',
          presenter() {
            let self = this;
            // 渲染模板
            let html = render(tpl, data);
            this.$el.innerHTML = html;
            // View上的改变通知Presenter改变Model和其他View
            $('#input').on('change', () => {
              self.model.text = this.value;
               html = render('{{text}}', self.model);
              $('#showText').html(html);
            });
            // 监听事件
            self.event['change'] = function() {
              self.model.text = '...';
              html = render('{{text}}', self.model);
              $('#showText').html(html);
            }                                                          
          }
        })
    </script>

    View和Model主要用于提供视图模板和数据而不做任何逻辑处理

    前端MVVM模式

    MVVM可认为是一个自动化的MVP,使用ViewModel代替了Presenter。数据Model的调用和模板内容的渲染不需要我们主动操作,而是ViewModel自动来触发完成,任何用户的操作也是通过ViewModel的改变驱动的。

    数据变更检测:

    方式 原理 说明
    手动触发绑定 通过在数据对象上定义get()、set()方法(函数中包含View层的渲染),手动触发 需要主动调用重新扫描HTML页面上的所有节点的方法
    脏检测机制 ViewModel对象的某个属性值发生变化时找到与这个属性值相关的所有元素,然后再比较数据变化,如果发生变化则进行Directive指令调用,对这个元素进行重新扫描渲染 只针对可能修改的元素进行扫描
    前端数据对象劫持 使用Object.definePropertyObject.defineProperties对ViewModel数据对象进行属性get()和set()的监听,当有数据读取和赋值等操作则扫描元素节点,运行指定节点的Directive指令。 对象和数组新增成员需要手动调用
    ES6 Proxy 在现有对象基础上重新定义一个对象,并重新定义对象原型上的方法,包括get()和set()。 ES6方式,存在兼容性

    Virtual DOM交互模式

    MVVM的前端交互模式大大提高了编程效率,自动双向数据绑定让我们可以将页面逻辑实现的核心转移到数据层的修改操作上,而不再是在页面中直接操作DOM。MVVM最终数据层反应到页面上View层的渲染和改变仍是通过对应的指令进行DOM操作来完成的,而且通过一次ViewModel的变化可能会触发页面上多个指令操作DOM的变化,带来大量的页面结构层DOM操作或渲染。

    <ul id="root">
      <li v-for="item in list">
        <a href="item.href">item.value</a>
      </li>
    </ul>
    <script>
        var root = new Vue({
          el: '#root',
          data() {
            return {
              list: [{href: '', value: ''},{href: '', value: ''}]
            }
          }
        })
    </script>

    在起初的MVVM框架中一般会重新渲染整个列表,包括列表中无需改变的部分也会重新渲染一次。但实际上如果直接操作改变DOM的话,只需变更或新的<li>做操作即可。所以,我们可以将新的Model data和旧的Model data进行对比,然后记录ViewModel的改变方式和位置,就知道怎样更新本次修改。

    这里写图片描述

    Virtual DOM是一个能够直接描述一段HTML DOM结构的JavaScript对象,浏览器可以根据它的结构按照一定规则创建出确定唯一的HTML DOM结构。

    Virtual DOM的核心实现:创建原始页面或组件的Virtual DOM结构,用户操作后需要进行DOM更新时,生成用户操作后页面或组件的Virtual DOM结构并与之前的结构进行对比,找到最小变换Virtual DOM的差异化描述对象,然后把差异化的Virtual DOM根据特定的规则渲染到页面上。

    这里写图片描述

    • 创建Virtual DOM:把一段HTML字符串文本解析成一个能够描述它的JavaScript对象。

      <ul id="root">
      <li>
          <a href="链接1">文本1</a>
      </li>
      <li>
          <a href="链接2">文本2</a>
      </li>
      </ul>
      <script>
      let ulElement = {
          tagName: 'ul',
          attribute: [{
            id: 'root'
          }],
          children: [{
            tagName: 'li',
            children: [{
              tagName: 'a',
              attribute: [{
                href: '链接1'
              }],
              nodeText: '文本1'
            }]
          },{
            tagName: 'li',
            children: [{
              tagName: 'a',
              attribute: [{
                href: '链接2'
              }],
              nodeText: '文本2'
            }]
          }]
      }
      </script>
    • 对比Virtual DOM:对比前后变化的两个Virtual DOM差异性,得到一个差异树对象。可使用广度优先算法和深度优先算法。这里需要记录节点改变的内容,还要记录发生差异化改变的类型和位置。

    • 渲染Virtual DOM:根据差异化内容将其渲染到页面上,减少了对DOM对象的操作次数。

    前端MNV*时代

    使用JavaScript调用原生控件或事件绑定来生成应用程序的交互模式称为前端MNV*开发模式。如果说Virtual DOM减少了DOM的交互次数,那么MNV*想要做的就是完全抛弃使用DOM。这种模式仅适用于移动端Hybrid应用,因为需要依赖原生应用控件的调用支持。将JSBridge和DOM编程的方式进行结合,让前端能够快速构建开发原生页面的引用,从而脱离DOM的交互模式。

    展开全文
  • 智能交互框架总结

    2018-02-03 16:06:47
    深度学习固然热络,但在垂直领域,我还是推崇规则匹配,垂直领域的正常问答中,不会超过10000条语句,那么规则其实能很好cover,准确率甚至... 智能交互总体框架 下面着重总结下自然语言理解(NLU)部分: 1. NLU分
  • mybatis数据库交互框架

    2018-11-13 08:24:15
    动态sql设计mybatis框架中特性之一,在一些组合查询页面需要根据用户输入得条件生成不同的查询sql语句,在jdbc或者其他像是框架中需要在代码中拼接sql容易出错,mybatis可以解决这种问题 动态sql标签与jstl相似,...
  • 今天的主角就是BUI交互框架, 又不仅仅只是框架, 这是一整套 快速开发Webapp的解决方案 . 请查看 BUI官网 , 里面有DEMO演示, 给你最直观的感受. 如果你也跟我一样在寻找一款快速开发的Webapp框架, 相信我,你来对...
  • 异步交互框架

    千次阅读 2013-03-18 14:29:34
     Ajax的一个核心是局部刷新,这里先回顾一下局部刷新的框架: ………… ………… 使用方法: 将要更新的区域,放到UpdatePanel的中,然后将触发更新的控件ID和事件名,放到区域...
  •  这个问题有很多种答案,在我所有项目中,交互框架的确定是非常重要,非常费时费力的,但是实际中又很容易被忽略,被轻视,入行的新人特别容易陷入到细节自我陶醉,而忘记产品的宏观建设。  这是很危险的。 ...
  • 【原文:... Kinect SDK v1.7 新特性、交互框架与新概念 zouxy09@qq.com http://blog.csdn.net/zouxy09    2013年3月18日,微软Kinect for Windows团队发布了新版的Kine
  • JavaScript与WebView交互框架设计

    千次阅读 2018-07-11 16:44:12
    如果这个交互框架是为了混合开发,那么应该约定不存在由native主动向js传递数据的情况,也就是交互都是由js发起的。如果需要native不断向js传递数据,那也应该由js先通知native“可以开始传了”。 数据协议 ...
  • Android需要与js进行交互,这里选用DSBridge,支持X5内核。
  •  InteractiveGraph 是一个使用JavaScript开发的开源项目,为大规模图数据提供了一个基于Web的交互操作框架,其数据可以来自于本地的GSON文件。  InteractiveGraph提供了3个基本应用,分别是图导航器...
  • H5与其他平台交互框架

    千次阅读 2016-07-10 11:16:01
    问题是,是否有人可以开发一个框架,让Web开发人员可以利用他们所有的HTML、CSS和JavaScript知识,而且仍旧可以同iPhone的重要本地应用程序(如摄像头和通讯录)交互呢? 就在那一年,PhoneGap获了奖并开始支持...
  • H5 Native WebView 交互框架及经验

    千次阅读 2016-08-23 20:51:13
    轻量级 H5 与 Native 交互的 Hybrid 框架轻量级 litehybrid,适合大多数android app 通过webview进行交互。 自定义loading,error动画,并有更好的回调结构等。
  • 1. 以 Path、Facebook 为代表的「左侧隐藏...以上几种交互框架各自的有点和缺陷是什么?应用如何根据需要选择合适的交互框架? 2 条评论 分享 按票数排序 10 个回答 赞同 反对,不会显示

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,678
精华内容 11,871
关键字:

交互框架