oc和js交互_js调用api

oc和js交互_js调用apiiOSJS与OC交互1、UIWebView与JS交互UIWebView在iOS12中已经被废弃,同时WKWebView在iOS8中已经出现。所以无特殊情况的话,我们一般应该也是用不到前者了!UIWebView初始化:self.webView=[[UIWebViewalloc]initWithFrame:self.view.bounds];self.webView.delegate=self;[self.viewaddSubview:self.

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

iOS JS与OC交互

1、UIWebView JS 与 OC 交互

UIWebView 在 iOS12 中已经被废弃,同时WKWebView在iOS8中已经出现。所以无特殊情况的话,我们一般应该也是用不到前者了!
UIWebView 相比于 WKWebView 的使用上会简单很多。

UIWebView 初始化:

    self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
    self.webView.delegate = self;
    [self.view addSubview:self.webView];
    // 加载本地 H5 文件
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil];
    NSURLRequest *reqeust = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:reqeust];

Jetbrains全家桶1年46,售后保障稳定

UIWebViewDelegate 协议的几个方法:

// 拦截JS页面操作请求,JS 调用OC 方法时会用到
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
// 开始加载页面
- (void)webViewDidStartLoad:(UIWebView *)webView;
// 页面加载完毕
- (void)webViewDidFinishLoad:(UIWebView *)webView;
// 页面加载失败
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;

1.1 OC 调用 JS 函数

OC 调用 JS 函数,有两种方法:

①使用stringByEvaluatingJavaScriptFromString,拼接 JS 字符串调用。
②使用 JSContext 上下文调用 JS 函数

第一种方法使用相对简单,但复杂业务可能无法实现。

1.1.1 OC 拼接 JS 字符串调用 JS 方法

JS 代码如下:

<!DOCTYPE html>
<html lang="en">
	<head>
	    <meta charset="UTF-8">
	    <title>OC与JS交互</title>
	    <script>
	        function showAlert_hasReturnValue(str){
	            alert('OC 调用JS ' + str);
	            return '返回值给OC';
	        }
	        function showAlert_noReturnValue(str){
	            alert('OC 调用JS ' + str);
	        }
	    </script>
	</head>
</html>

OC 中调用 JS 函数,是将 JS 拼接成字符串,作为 stringByEvaluatingJavaScriptFromString 方法的参数实现的。

/** OC 调用 JS 无返回值 */
- (IBAction)didClickLeftItem:(id)sender {
    [self.webView stringByEvaluatingJavaScriptFromString:@"showAlert_noReturnValue('无返回值')"];
}
/** OC 调用 JS 有返回值 */
- (IBAction)didClickRightItem:(id)sender {
    // OC --> JS 有返回值
    NSString *resString = [self.webView stringByEvaluatingJavaScriptFromString:@"showAlert_hasReturnValue('有返回值')"];
    NSLog(@"%@", resString);
}

1.1.2 使用 JSContext 上下文环境调用 JS 函数

UIWebView 加载完成时,初始化上下文环境:

#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.context = context;
}
#pragma mark - 响应
/** OC 调用 JS 无返回值 */
- (IBAction)didClickLeftItem:(id)sender {
    NSDictionary *dict = @{@"name": @"kangpp", @"age": @28};
    // 上下文调用 JS 函数
    [self.context[@"ocCallJS_byJSContext"] callWithArguments:@[dict]];
}

1.2 JS 调用 OC 函数

JS 调用 OC 函数有三种实现方式:

webView: shouldStartLoadWithRequest: 协议中拦截 JS 操作。
② 使用 JavaScriptCore,向 JS 中注册 OC 类,JS 函数中直接调用 OC 方法。
③ 使用 JSContext 上下文,JS 回调 OC 代码块。

1.2.1 OC 拦截 JS 超链接操作请求

HTML 文件中,需要调用 OC 方法的标签,添加超链接属性(超链接协议可自定义)。那么该标签的操作将在 UIWebViewDelegate 协议方法 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 中被监听拦截。
JS 文件如下:

<!DOCTYPE html>
<html lang="en">
	<head>
	    <meta charset="UTF-8">
	    <title>OC与JS交互</title>
	    <script>
	    </script>
	</head>
	<body>
	    <div>
	        <a href="kpp://jsCallOC:/helloword/js">JS 调用 OC 方法(该标签的操作将被 OC 拦截)
	        </a>
	    </div>
	</body>
</html>

当点击 <a> 标签时,在 下方协议方法中我们将从request中获取URL信息:

#pragma mark - UIWebViewDelegate
// 加载所有请求数据,以及控制是否加载
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    // URL ==> kpp://jsCallOC:/helloword/js
    NSURL *requestURL = request.URL;
    // URL 的一般格式为 scheme://host:port/path?
    NSString *scheme = requestURL.scheme;
    NSString *host = requestURL.host;
    NSNumber *port = requestURL.port;
    NSArray *paths = requestURL.pathComponents;
    // URL 全路径字符串
    NSString *absoluteString = requestURL.absoluteString;
    // 端口后的相对路径
    NSString *path = requestURL.path;
    return YES;
}

根据以上从 URL 中获取的数据,可以在此设置路由调用 OC 中指定的方法。前提当然是自己协商一致 URL 数据格式。

#pragma mark - UIWebViewDelegate
// 加载所有请求数据,以及控制是否加载
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    // request : host + 路由  : 拦截
    if ([request.URL.scheme isEqualToString:@"kpp"]) {
        // 方法名 kpp://jsCallOC:/helloword/js
        NSString *routerName = request.URL.host;
        SEL methodSEL = NSSelectorFromString(routerName);
        // 测试方法为 jsCallOC
        NSLog(@"routerName => %@", routerName);
        if ([self respondsToSelector:methodSEL]) {
            objc_msgSend(self,methodSEL,@"");
        } else {
            NSLog(@"没有找到对应的路由方法");
        }
        return NO;
    }
    return YES;
}
/** JS 调用 OC 的响应方法 */
- (void)jsCallOC {
    NSLog(@"被JS调用的方法!");
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"提示" message:@"JS调用OC方法" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
    [controller addAction:okAction];
    [self presentViewController:controller animated:YES completion:nil];
}

1.2.2 向 JS 中注入 OC 类

向 JS 注入 OC 类,需要引入 <JavaScriptCore/JavaScriptCore.h> 框架,使用 JSContext 向 JS 中注入 OC 类。
同时,被 JS 调用的 OC 方法,需要遵守 JSExport 协议。
例如,需求为 JS 调用 OC 的 getUserInfo 方法,获取应用内用户信息。
首先,要将该方法使用协议约定,并继承JSExport 协议:

@protocol TestProtocol <JSExport>
- (NSString *)getUserInfo;
@end

然后在注入JS的类中遵守TestProtocol协议并实现 getUserInfo 方法 ,demo中直接在控制器实现:

@interface ViewController ()<UIWebViewDelegate, TestProtocol>
@property (nonatomic, strong) UIWebView *webView;
@end

当 UIWebView 加载完成的时候,使用JSContext 向 WebView 中注入OC类:

#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    // 可以注入实例对象也可以注入类对象
    context[@"ViewController"] = self;
}

相应的在JS 中,可以直接使用 OC 类和方法调用:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>OC与JS交互</title>
        <script>
            function getUserInfo() {
            	// 注入OC类以后,此处通过OC类名可直接调用
                var val = ViewController.getUserInfo();
                alert(val);
            }
        </script>
    </head>
    <body>
        <input type="button" value="注入OC类的方式 调用OC方法,并获取返回值" onClick="getUserInfo()" />
    </body>
</html>

1.2.3 使用 JSContext 上下文,JS函数 回调 OC 代码块

JS 代码中blockOCCode()就是执行的OC代码块,如下:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>OC与JS交互</title>
        <script>
            function jsCallOC_byJSContext() {
                // arr 是 OC 注入的全局属性,可以在此处处理后,传递给OC
                // 对注入的属性,做业务处理后返回给 OC
                arr.splice(0, 1)
                blockOCCode(arr)
            }
        </script>
    </head>
    <body>
        <input type="button" value="JS 调用 OC 方法(JS 回调 OCBlock 代码块)" onClick="jsCallOC_byJSContext()" />
    </body>
</html>

同理,在OC代码中,当页面加载完毕,就要拿到上下文的引用,注入属性及blockOCCode 代码块赋值:

#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
	// 拿到 JS 上下文引用
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.context = context;
    self.context[@"ViewController"] = self;
    // js 中注入全局变量
    [context evaluateScript:@"var arr = ['张三', '李四', '王五', '赵六']"];
    context[@"blockOCCode"] = ^(NSArray *jsArr){
        // jsArr 是 JS 传递给 OC代码块的参数
        NSLog(@"blockOCCode->jsArr == %@", jsArr);
        // 通过上下文拿到 JS 全局属性
        //NSArray *orgArr = [JSContext currentArguments];
        //NSLog(@"blockOCCode->orgArr == %@", orgArr);
    };
}

如此即可实现 JS 回调 OC 代码块。

1.3 异常收集

JS 异常收集代码:

#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // 异常收集
    self.context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        NSLog(@"%@",exception);
    };
}

2、WKWebView OC 与 JS 交互

WKWebView 初始化:

    // 配置类
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    // 适配移动设备
    NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
    WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
    WKUserContentController *wkUController = [[WKUserContentController alloc] init];
    [wkUController addUserScript:wkUScript];
    configuration.userContentController = wkUController;
    // 初始化 WebView
    self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];
    // <WKUIDelegate, WKNavigationDelegate>
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
    // 加载(本地) H5 文件
    NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"WKWebView_Index.html" ofType:nil];
    NSURL *fileURL = [NSURL fileURLWithPath:urlStr];
    [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];

2.1 WKUIDelegate 协议

常用该协议替换 JS 弹窗提示,以获得更好的用户体验。

// 创建一个新的 WebView 视图时调用
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
// 视图关闭时调用
- (void)webViewDidClose:(WKWebView *)webView;
// JS 警告框调用
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
// JS 确认框调用
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
// JS prompt()函数,该方法会被执行
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;

2.2 OC 调用 JS 函数

OC 调用 JS 是通过 evaluateJavaScript: completionHandler: 方法实现的,JS 代码比较简单:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
            <title>OC与JS交互</title>
            <script>
                function ocCallJS(str) {
                    alert("OC ---> JS" + str);
                    <!-- return value 通过 evaluateJavaScript: completionHandler: 回调中的值传递给OC -->
                    return "ocCallJS return value";
                }
            </script>
    </head>
</html>

OC 代码也不难:

/** OC 调用 JS 返回值在 completionHandler 的回调参数 result 里 */
- (IBAction)didClickRightItem:(id)sender {
    // OC --> JS 有返回值
    NSString *jsStr = @"ocCallJS('WK_ocCallJS:OC-->JS')";
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        // result 是 JS return 回来的值
        NSLog(@"%@----%@",result, error);
    }];
}

2.3 JS 调用 OC

WKWebView 中 JS 调用 OC 函数有两种实现方式:

① 使用 WKNavigationDelegate 协议 webView: decidePolicyForNavigationAction: decisionHandler: 方法拦截 JS 操作请求。
② 使用 WKScriptMessageHandler 协议 userContentController: didReceiveScriptMessage: 方法,接收 JS 发来的特定消息进行解析处理。

2.3.1 拦截 JS 超链接请求

HTML 文件中,需要调用 OC 方法的标签,添加超链接属性(超链接协议可自定义)。那么该标签的操作将在 WKNavigationDelegate 协议方法 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler 中被监听拦截。
JS 代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
            <title>OC与JS交互</title>
    </head>
    <body>
        <div>
            <a href="kpp://WKWebView_jsCallOC:/helloword/js"> WK 中调用OC  </a>
        <div/>
        <br />         
     </body>
</html>

OC 中拦截,并使用路由调用指定 OC 方法:

#pragma mark - WKNavigationDelegate
// 拦截 JS 代码中的 请求操作
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    if ([navigationAction.request.URL.scheme isEqualToString:@"kpp"]) {
        NSString *routerName = navigationAction.request.URL.host;
        SEL methodSEL = NSSelectorFromString(routerName);
        NSLog(@"routerName => %@", routerName);
        if ([self respondsToSelector:methodSEL]) {
            objc_msgSend(self,methodSEL,@"");
            
        } else {
            NSLog(@"没有相应路由");
        }
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}
// 被 JS 调用的 OC 方法
- (void)WKWebView_jsCallOC {
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"提示" message:@"WK 中JS调用OC方法" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
    [controller addAction:okAction];
    [self presentViewController:controller animated:YES completion:nil];
}

2.3.2 OC 接收 JS 发来的消息

该方法使用步骤上相对繁琐,但 WKScriptMessageHandler 协议中只有一个方法userContentController: didReceiveScriptMessage:
① 引入 WKScriptMessageHandler 协议,并使用 config 初始化 WKWebView。
② 注册 ScriptMessageHandler
③ 实现协议方法。
④ 移除 ScriptMessageHandler

JS 代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
            <title>OC与JS交互</title>
            <script>
                function jsSendMessage(){
                    // js 发送消息, messgaeToOC 是在 OC 代码中注册过的名称
                    var val =  window.webkit.messageHandlers.messgaeToOC.postMessage("js 发送给 OC 的消息");
                    alert(val);
                }
            </script>
    </head>
    <body>
        <div>
            <input type="button" value="messgaeHandle" onClick="jsSendMessage()" />
        <div/>
        <br />
     </body>
</html>

OC 代码实现步骤:

// ① 引入协议
@interface KYWKContorller ()<WKScriptMessageHandler>
// ② 注册消息处理名称为:messgaeToOC
- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"messgaeToOC"];
}
// ③ 实现协议方法
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
	// message.name 就是我们注册的 messgaeToOC
	// message.body 就是JS发送过来的消息
    NSLog(@"%@---%@",message.name, message.body);
    // 根据这两个参数 写我们的业务代码
    ... ...
}
// ④ 控制器销毁时移除 `ScriptMessageHandler`
- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"messgaeToOC"];
}

3、第三方库实现 OC 与 JS 交互

3.1 WebViewJavascriptBridge 库使用

该节介绍的第三方库是:WebViewJavascriptBridge
该库支持 UIWebViewWKWebView。使用比较简单,上手容易。
使用步骤:

① 引入头文件
② 初始化桥接类实例
③ (JS 调用 OC)OC中 registerHandler 注册JS方法,使用block传参及回调;( OC 调用 JS)callHandler 调用 JS 方法,使用block回调JS返回结果。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>OC与JS交互</title>
    <script>
       <!-- 使用该库,JS 中代码中需要添加:-->
       function setupWebViewJavascriptBridge(callback) {
           if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
           if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
           window.WVJBCallbacks = [callback];
           var WVJBIframe = document.createElement('iframe');
           WVJBIframe.style.display = 'none';
           WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
           document.documentElement.appendChild(WVJBIframe);
           setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
       }
        setupWebViewJavascriptBridge(function(bridge) {
         // JS 被调用的方法  OCCallJSFunction 定义的标识
            bridge.registerHandler('OCCallJSFunction', function(data, responseCallback) {
                alert('JS方法被调用:' + data);
                responseCallback('OC调用的JS方法已被执行');
            })
         })          
         function jsCallsOCFunc(){
            WebViewJavascriptBridge.callHandler('jsCallsOC', {'name': 'kpp'}, function(response) {
                alert(response);
            })
         }
    </script>
</head>
<body>
    <div>
        <input type="button" value="JS 调用 OC 方法" onclick="jsCallsOCFunc()" /> <br />
    <div/>
    <br />
    <div>
        <a href="kpp://WKWebView_jsCallOC:/helloword/js"> WK 中调用OC (不使用第三方)  </a>
    <div/>
    <br />
</body>
</html>

OC 代码实现:

#import "WebViewJavascriptBridge.h"
@property (strong, nonatomic) WKWebView   *webView;
@property (nonatomic, strong) WebViewJavascriptBridge *wjb;
- (void)createWjb {
	// 初始化桥接类实例
    self.wjb = [WebViewJavascriptBridge  bridgeForWebView:self.webView];
    // 设置 WKNavigationDelegate 代理,保留该协议使用者依然可用
    [self.wjb setWebViewDelegate:self];
}
/** JS 调用 OC 方法 */
- (void)jsCallOC {
    // JS-->OC
    [self.wjb  registerHandler:@"jsCallsOC" handler:^(id data, WVJBResponseCallback responseCallback) {
        // data 是 JS 传递给OC 的参数,responseCallback可将执行结果回调给 JS
        NSLog(@"%@---%@----%@",[NSThread currentThread],data,responseCallback);
        responseCallback(@"JS调用的OC方法已执行");
    }];
}
/** OC 调用 JS 方法 */
- (void)OCCallJS {
    [self.wjb callHandler:@"OCCallJSFunction" data:@"传递参数param" responseCallback:^(id responseData) {
        // data 是 OC 传递给 JS 的参数,responseData是 JS 执行完成后回调给OC 的执行结果
        NSLog(@"%@--%@",[NSThread currentThread],responseData);
    }];
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/206864.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Ignoring query to other database

    Ignoring query to other database

  • 域渗透之MS14-068域提权漏洞

    域渗透之MS14-68域提权漏洞漏洞概述漏洞可能允许攻击者将未经授权的域用户账户的权限,提权到域管理员的权限。利用条件域控机器没有打MS14-068的补丁(KB3011780)需要一个域内用

    2021年12月13日
  • Python之struct

    1.功能(1)按照指定格式将Python数据转换为字符串(该字符串为字节流)(2)按照指定格式将字节流转换为Python指定的数据类型(3)处理二进制数据,如果用struct来处理文件的

    2021年12月18日
  • 婴儿照片大全可爱萌萌_好萌图片

    婴儿照片大全可爱萌萌_好萌图片萌翻了!这是一组可爱的婴儿照片,你可以从中学习到优秀的婴儿照片拍摄技术。就像我以前说的,婴儿总是持续在运动,因此很难找到一个好的角度。拍摄的时候,试着和婴儿保持同一水平,使用长de焦距。特别在最初几

  • npm更新命令行[通俗易懂]

    查看自己npm,跟node版本:npm-vnode-v使用命令行升级npm:npminstallnpm@latest-g

  • FTP下载工具的使用

    FTP下载工具的使用针对遇到的某些FTP的资源无法下载,或者下载容易中断的问题,FTP下载工具帮你完美的解决这个问题。首先下载FTP工具,目前网上大家都推荐的FlashFXP5.1.0.3829官方中文版。PS:给个链接http://dl.pconline.com.cn/html_2/1/89/id=61&pn=0.html#ad=7366下载完成后直接安装运行就可以,同普通软件一样,给个截图如

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号