關(guān)于iOS中原生和h5交互的知識(shí)總結(jié)(二)WKWebView

前言

目錄

關(guān)于iOS中原生和h5交互的知識(shí)總結(jié)(一)UIWebView
關(guān)于iOS中原生和h5交互的知識(shí)總結(jié)(二)WKWebView

基于WKWebView的實(shí)現(xiàn),請(qǐng)注意以下幾點(diǎn)(可以全局搜索1~7查看代碼中對(duì)應(yīng)位置)

1.初始化
2.清理緩存
3.進(jìn)度條
4.代理方法
5.交互*
6.addScriptMessageHandler導(dǎo)致不釋放問題*
7.響應(yīng)localStorage變化事件*

樣例

我們寫一個(gè)基類WebViewController,之后所有用到WKWebView的controller都可以繼承這個(gè)基類,省著我們?cè)偃ピ诿總€(gè)controller中再去寫一些關(guān)于webView的初始化,配置,代理等一堆東西了
WebViewController.h

#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@interface WebViewController : UIViewController

//跳轉(zhuǎn)到該controller時(shí)需要加載的頁面url
@property (nonatomic, copy) NSString *url;
//是否顯示導(dǎo)航欄
@property (nonatomic, assign) BOOL hideNavigationBar;
//暴露進(jìn)度條,方便子類修改樣式,如果進(jìn)度條樣式全局統(tǒng)一,可以不暴露
@property (nonatomic, strong) UIProgressView *progressView;
//暴露webView,用于子類loadRequest
@property (nonatomic, strong) WKWebView *webView;
//暴露WKUserContentController,如果素有WKUserContentController操作都在基類中,可以不暴露
@property (nonatomic, strong) WKUserContentController *controller;

@end

WebViewController.m

#import "WebViewController.h"
#import "WebViewConstant.h"
#import "WebLoadingView.h"
#import "NotifyConstant.h"
#import "ProgressPoolSingleton.h"
#import "WeakScriptMessageDelegate.h"

#import "NavigationController.h"
#import "SendTableViewController.h"
#import "LoginTableViewController.h"
#import "VideoBrowseController.h"
#import "MemberAuthStatusViewController.h"

@interface WebViewController ()<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler,UITabBarControllerDelegate,UIScrollViewDelegate,UINavigationControllerDelegate>
@property (nonatomic, assign) CGFloat contentOffsetY;
@end

@implementation WebViewController

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

//默認(rèn)隱藏狀態(tài)欄
- (id)init
{
    self = [super init];
    if (self) {
        _hideNavigationBar = YES;
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        _hideNavigationBar = YES;
    }
    return self;
}

//釋放時(shí),移除KVO和scriptMessageHandler
- (void)dealloc
{
    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    [self.controller removeScriptMessageHandlerForName:@"getToken"];
    [self.controller removeScriptMessageHandlerForName:@"showWebScene"];
    [self.controller removeScriptMessageHandlerForName:@"showSendScene"];
    [self.controller removeScriptMessageHandlerForName:@"exitScene"];
    [self.controller removeScriptMessageHandlerForName:@"showLoginScene"];
    [self.controller removeScriptMessageHandlerForName:@"showVideoPlayScene"];
    [self.controller removeScriptMessageHandlerForName:@"showMemberCertificationScene"];
}

//添加addScriptMessageHandler
//WeakScriptMessageDelegate這個(gè)類是防止添加到self,導(dǎo)致不能釋放的問題
//6.addScriptMessageHandler導(dǎo)致不釋放問題
- (void)addScriptMessageHandler
{
    WeakScriptMessageDelegate *delegate = [[WeakScriptMessageDelegate alloc] initWithDelegate:self];
    [self.controller addScriptMessageHandler:delegate name:@"getToken"];
    [self.controller addScriptMessageHandler:delegate name:@"showWebScene"];
    [self.controller addScriptMessageHandler:delegate name:@"showSendScene"];
    [self.controller addScriptMessageHandler:delegate name:@"exitScene"];
    [self.controller addScriptMessageHandler:delegate name:@"showLoginScene"];
    [self.controller addScriptMessageHandler:delegate name:@"showVideoPlayScene"];
    [self.controller addScriptMessageHandler:delegate name:@"showMemberCertificationScene"];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.contentOffsetY = self.hideNavigationBar == YES ? 20 : 0;
    self.view.backgroundColor = [UIColor colorWithRed:150.0/255.0 green:0 blue:10.0/255.0 alpha:1];
    self.navigationController.delegate = self;

    self.webView.scrollView.delegate = self;
    self.webView.scrollView.bounces = NO;

    // 1.初始化
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    self.controller = [[WKUserContentController alloc] init];
    [self addScriptMessageHandler];
    
    //7.響應(yīng)localStorage變化事件
    configuration.userContentController = self.controller;
    configuration.processPool = [ProgressPoolSingleton sharedInstance].processPool;

    self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, self.contentOffsetY, self.view.bounds.size.width, self.view.bounds.size.height-20) configuration:configuration];
    self.webView.scrollView.bounces = YES;
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
    //3.進(jìn)度條
    [self.view addSubview:self.progressView];
    //觀察加載進(jìn)度
    [self.webView addObserver:self forKeyPath:@"estimatedProgress"
                      options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil];

    if (self.url) {
        [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.url]]];
    }
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refresh) name:HRefreshWebVCNotification object:nil];
    [[WebLoadingView sharedInstance] showOnView:self.view];
    
//    [self debugButton];
}

//調(diào)試按鈕
- (void)debugButton
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    [button setTitle:@"點(diǎn)我" forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor greenColor]];
    button.frame = CGRectMake(0, 400, 100, 100);
    [button addTarget:self action:@selector(debugButtonAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}

//2.清理緩存
- (void)debugButtonAction
{
    NSSet *websiteDataTypes = [NSSet setWithObjects:WKWebsiteDataTypeDiskCache,WKWebsiteDataTypeOfflineWebApplicationCache,WKWebsiteDataTypeMemoryCache,WKWebsiteDataTypeLocalStorage,nil];
    NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
    
    @weakify(self)
    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
        @strongify(self)
        [self.webView reload];
    }];
}

- (void)refresh
{
    [self.webView reload];
}

- (void)keyboardWillShow:(NSNotification *)notifycation
{

}

- (void)keyboardWillHide:(NSNotification *)notifycation
{
    
}

//控制是否顯示導(dǎo)航條
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if ([viewController isEqual:self]) {
        [self.navigationController setNavigationBarHidden:self.hideNavigationBar animated:YES];
    } else {
        if ([viewController isKindOfClass:WebViewController.class]) {
            [self.navigationController setNavigationBarHidden:((WebViewController *)viewController).hideNavigationBar animated:YES];
        } else {
            [self.navigationController setNavigationBarHidden:YES animated:YES];
        }
    }
}

#pragma mark - KVC
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (object == self.webView && [keyPath isEqualToString:@"estimatedProgress"]) {
        CGFloat newprogress = [[change objectForKey:NSKeyValueChangeNewKey] doubleValue];
        if (newprogress == 1) {
            self.progressView.hidden = YES;
            [self.progressView setProgress:0 animated:NO];
        }else {
            self.progressView.hidden = NO;
            [self.progressView setProgress:newprogress animated:YES];
        }
    }
}

//5.交互
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSDictionary *dictionary = message.body;
    NSString *nativeCallback;
    if (dictionary &&
        [dictionary isKindOfClass:NSDictionary.class]) {
        nativeCallback = dictionary[NATIVE_CALLBACK];
    }
    
    if ([message.name isEqualToString:@"getToken"]) {
        
        NSString *token = [[[LocalSaveManager sharedInstance] getToken] translateN];
        NSString *responseToken;
        
        if (token) {
            responseToken = [NSString stringWithFormat:@"'%@'",token];
        } else {
            responseToken = @"'invalid_token'";
        }
        
        NSString *evaluateJavaScript = [NSString stringWithFormat:@"%@(%@)",nativeCallback,responseToken];
        
        @weakify(self)
        dispatch_async(dispatch_get_main_queue(), ^ {
            @strongify(self)
            [self.webView evaluateJavaScript:evaluateJavaScript completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                NSLog(@"result:%@",result);
                NSLog(@"error:%@",error);
            }];
        });
    } else if ([message.name isEqualToString:@"exitScene"]) {
        [self.navigationController popViewControllerAnimated:YES];
    } else if ([message.name isEqualToString:@"showWebScene"]) {
        WebViewController *webViewController = [[WebViewController alloc] init];
        webViewController.hidesBottomBarWhenPushed = YES;
        BOOL hideNavigationBar = [dictionary[@"hideNavigationBar"] boolValue];
        webViewController.hideNavigationBar = hideNavigationBar;
        webViewController.url = dictionary[@"url"];
        [self.navigationController pushViewController:webViewController animated:YES];
    } else if ([message.name isEqualToString:@"showSendScene"]) {
        NSString *token = [[LocalSaveManager sharedInstance] getToken];
        if (token) {
            SendTableViewController *sendTableViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"SendTableViewController"];
            [self.navigationController pushViewController:sendTableViewController animated:YES];
        } else {
            LoginTableViewController *loginTableViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"LoginTableViewController"];
            NavigationController *nav = [[NavigationController alloc] initWithRootViewController:loginTableViewController];
            [self presentViewController:nav animated:YES completion:nil];
        }
    } else if ([message.name isEqualToString:@"showLoginScene"]) {
        LoginTableViewController *loginTableViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"LoginTableViewController"];
        NavigationController *nav = [[NavigationController alloc] initWithRootViewController:loginTableViewController];
        [self presentViewController:nav animated:YES completion:nil];
    } else if ([message.name isEqualToString:@"showVideoPlayScene"]) {
        VideoBrowseController *videoBrowseController = [[VideoBrowseController alloc] init];
        videoBrowseController.videoUrl = dictionary[@"video_url"];
        videoBrowseController.thumbnail = dictionary[@"thumbnail_url"];
        [self presentViewController:videoBrowseController animated:YES completion:nil];
    } else if ([message.name isEqualToString:@"showMemberCertificationScene"]) {
        NSString *token = [[LocalSaveManager sharedInstance] getToken];
        if (token) {
            MemberAuthStatusViewController *memberAuthStatusViewController = [[UIStoryboard storyboardWithName:@"Service" bundle:nil] instantiateViewControllerWithIdentifier:@"MemberAuthStatusViewController"];
            NavigationController *nav = [[NavigationController alloc] initWithRootViewController:memberAuthStatusViewController];
            [self presentViewController:nav animated:YES completion:nil];
        } else {
            LoginTableViewController *loginTableViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"LoginTableViewController"];
            NavigationController *nav = [[NavigationController alloc] initWithRootViewController:loginTableViewController];
            [self presentViewController:nav animated:YES completion:nil];
        }
    } else {
        
    }
}

//4.代理方法
#pragma mark - WKUIDelegate
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
    completionHandler();
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *action = [UIAlertAction actionWithTitle:@"確認(rèn)" style:UIAlertActionStyleDefault handler:nil];
    [alertController addAction:action];
    [self presentViewController:alertController animated:YES completion:nil];
}

#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation
{
    //    [self rotate];
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
    //    [self stopRotation];
    [[WebLoadingView sharedInstance] hide];
}

- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
{
    //    [self stopRotation];
    [[WebLoadingView sharedInstance] hide];
}

#pragma mark - get method
- (UIProgressView *)progressView
{
    if (!_progressView)
    {
        _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, self.contentOffsetY, self.view.bounds.size.width, 2)];
        _progressView.tintColor = [UIColor greenColor];
        _progressView.trackTintColor = [UIColor whiteColor];
    }
    return _progressView;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

解答1.2.3.4請(qǐng)自行百度吧,這里主要說下5.6.7

5.交互*

6.addScriptMessageHandler導(dǎo)致不釋放問題*

WKWebView和UIWebView js與原生交互是完全不同的,我們需要向messageHandlers中注冊(cè)標(biāo)識(shí),js端通過這些標(biāo)識(shí)來與原生交互,WeakScriptMessageDelegate是解決問題6,下面會(huì)給出代碼

WeakScriptMessageDelegate *delegate = [[WeakScriptMessageDelegate alloc] initWithDelegate:self];
[self.controller addScriptMessageHandler:delegate name:@"getToken"];
[self.controller addScriptMessageHandler:delegate name:@"showWebScene"];
[self.controller addScriptMessageHandler:delegate name:@"showSendScene"];
[self.controller addScriptMessageHandler:delegate name:@"exitScene"];
[self.controller addScriptMessageHandler:delegate name:@"showLoginScene"];
[self.controller addScriptMessageHandler:delegate name:@"showVideoPlayScene"];
[self.controller addScriptMessageHandler:delegate name:@"showMemberCertificationScene"];

然后在WKScriptMessageHandler的代理方法中去處理這些標(biāo)識(shí)(完整代碼見WebViewController.m),這里著重說一下getToken()這個(gè)方法,還記得講UIWebView的時(shí)候嗎,token是可以直接return回去的??墒窃赪KWebView中是沒法在下面的代理方法寫return的,所以js調(diào)用原生后,原生要給js傳值,只能通過下面的方法

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSDictionary *dictionary = message.body;
    NSString *nativeCallback;
    //nativeCallback是js端定義的方法,native端取到j(luò)s端定義的方法名后帶著token去執(zhí)行js端的這個(gè)方法,取到的就是js端定義的 getTokenCallback這個(gè)方法名
    if (dictionary &&
        [dictionary isKindOfClass:NSDictionary.class]) {
        nativeCallback = dictionary[NATIVE_CALLBACK];
    }
    
    if ([message.name isEqualToString:@"getToken"]) {
        
       //獲取native端的token
        NSString *token = [[[LocalSaveManager sharedInstance] getToken] translateN];
        NSString *responseToken;
        
        if (token) {
            responseToken = [NSString stringWithFormat:@"'%@'",token];
        } else {
            responseToken = @"'invalid_token'";
        }
        
       //拼接js端的方法和native的token作為方法參數(shù),然后執(zhí)行,把token回傳給js端
        NSString *evaluateJavaScript = [NSString stringWithFormat:@"%@(%@)",nativeCallback,responseToken];
        
        @weakify(self)
        dispatch_async(dispatch_get_main_queue(), ^ {
            @strongify(self)
            [self.webView evaluateJavaScript:evaluateJavaScript completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                NSLog(@"result:%@",result);
                NSLog(@"error:%@",error);
            }];
        });
    } 
}

下面給出WeakScriptMessageDelegate類的代碼
WeakScriptMessageDelegate.h

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>

@property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate;

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;

@end

WeakScriptMessageDelegate.m

#import "WeakScriptMessageDelegate.h"

@implementation WeakScriptMessageDelegate

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
    self = [super init];
    if (self) {
        _scriptDelegate = scriptDelegate;
    }
    return self;
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}

@end

接下來附上js端的調(diào)用代碼,js端的代碼不太想解釋了,看不懂的同學(xué)多看幾眼相信會(huì)看懂的

function isAndroid() {
    var u = navigator.userAgent;
    var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
    return isAndroid;
}

function isIOS() {
    var u = navigator.userAgent;
    var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
    return isIOS;
}

// public
// {
//  request:request,
//  callback:callback,
// }
var getTokenOptionCallback = null;
function getToken(option) {
    option = option || {};
    option.request = option.request || {};
    option.callback = option.callback || function () {};
    option.complete = option.complete || false;
    option.response = option.response || {};

    if (isIOS()) {
        if (option.complete != true) {
            getTokenOptionCallback = option.callback;
            option.request.nativeCallback = "getTokenCallback";
            window.webkit.messageHandlers.getToken.postMessage(option.request);
        } else {

            option.callback = getTokenOptionCallback;
            option.callback(option.response);
        }
    } else if (isAndroid()) {
        var token = jsObject.getToken(option.username);
        option.callback(token);
    }
}

// private (called by native)
// response
// be same with option.request.nativeCallback
function getTokenCallback(response) {
    var complete = true;
    getToken({
        complete:complete,
        response:response,
    });
}

// public , don't need nativeCallback
function showWebScene(url,hideNavigationBar) {
    if (isIOS()) {
        window.webkit.messageHandlers.showWebScene.postMessage({"url":url});
    } else if (isAndroid()) {
        jsObject.showWebScene();
    }
}

// public , don't need nativeCallback
function showSendScene() {
    if (isIOS()) {
        window.webkit.messageHandlers.showSendScene.postMessage(null);
    } else if (isAndroid()) {
        jsObject.showSendScene();
    }
}

// public , don't need nativeCallback
function exitScene() {
    if (isIOS()) {
        window.webkit.messageHandlers.exitScene.postMessage(null);
    } else if (isAndroid()) {
        jsObject.exitScene();
    }
}

// public , don't need nativeCallback
function showLoginScene() {
    if (isIOS()) {
        window.webkit.messageHandlers.showLoginScene.postMessage(null);
    } else if (isAndroid()) {
        jsObject.exitScene();
    }
}

// public , don't need nativeCallback
function showVideoPlayScene(thumbnail_url,video_url) {
    var parameter = {
        "thumbnail_url":thumbnail_url,
        "video_url":video_url
    };
    if (isIOS()) {
        window.webkit.messageHandlers.showVideoPlayScene.postMessage(parameter);
    } else if (isAndroid()) {
        jsObject.showVideoPlayScene(parameter);
    }
}
getToken({
   request:{
      username:'hliu',
      password:'123456',
  },callback:function(token) {
      alert(x+","+token);
  },
});

7.響應(yīng)localStorage變化事件*

不清楚localStorage事件及用途的同學(xué)可以自行百度一下,簡單說下我們當(dāng)時(shí)的需求,我們從A界面通過導(dǎo)航控制器跳轉(zhuǎn)到B界面,然后希望,B界面的修改能在A界面中得到響應(yīng),在safari中試了,不同窗口間是可以響應(yīng)localStorage變化事件的,可是在iOS中卻死活的不行。后來經(jīng)過調(diào)研終于知道原因,每個(gè)WKWebView的實(shí)例都會(huì)有自己的進(jìn)程池WKProcessPool,不同進(jìn)程池中是不能及時(shí)響應(yīng)localStorage變化的,所以現(xiàn)在是讓所有的WKWebView使用同一個(gè)進(jìn)程池,就能讓不同的WKWebView及時(shí)的響應(yīng)localStorage變化事件

    configuration.userContentController = self.controller;
    configuration.processPool = [ProgressPoolSingleton sharedInstance].processPool;

下面給出ProgressPoolSingleton的代碼
ProgressPoolSingleton.h

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
@interface ProgressPoolSingleton : NSObject

+ (instancetype)sharedInstance;

@property (nonatomic, strong) WKProcessPool *processPool;

@end

ProgressPoolSingleton.m

#import "ProgressPoolSingleton.h"

@implementation ProgressPoolSingleton

+ (instancetype)sharedInstance
{
    static ProgressPoolSingleton *progressPoolSingleton;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        progressPoolSingleton = [[ProgressPoolSingleton alloc] init];
    });
    return progressPoolSingleton;
}

- (id)init
{
    self = [super init];
    if (self) {
        self.processPool = [WKProcessPool new];
    }
    return self;
}

@end

附上js樣例代碼
storage_event.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
</head>
<body>

    <div id="ddd">數(shù)字</div>
    <script type="text/javascript">

        var storage = window.localStorage;
        var value = parseInt(storage.count_n);
        document.getElementById("ddd").innerHTML = value;

        window.addEventListener('storage', onStorageChange);

        function onStorageChange(e) {
            console.log(e.key);
            console.log(e.newValue);

            var value = parseInt(storage.count_n);
            document.getElementById("ddd").innerHTML = value;
        }


    </script>
</body>
</html>

storage_dispach.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
</head>
<body>
    <script type="text/javascript" >

        var index = 0;
        if (localStorage.count_n == undefined) {
            localStorage.count_n = index;
        }

        function clickMethod() {
            var value = parseInt(localStorage.count_n) + 1;
            localStorage.count_n = value;
            alert(value);
        }
    </script>

    In Page 1
    <button id="addBtn"
            onclick="clickMethod();">
            Add
    </button>
    <button id="clearBtn"
            onclick="localStorage.clear()">
            Clear
    </button>
</body>
</html>

再附上我的web相關(guān)目錄


屏幕快照 2018-01-24 下午2.45.45.png

總結(jié)

講解的可能有些粗糙,不過附上了大量代碼,小伙伴們看了,應(yīng)該會(huì)有所收獲的。日后還會(huì)對(duì)文章進(jìn)行修改,完善,增加新的內(nèi)容。還有哪兒不懂的小伙伴,歡迎留言,我會(huì)一一解答。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容