前端基础进阶,继承的实现方式及原型概述

2019-11-03 11:37栏目:人才招聘
TAG:

李秉骏:在Phonegap下实现oAuth认证

2012/07/18 · HTML5 · 2 评论 · 来源: 李秉骏     · HTML5

本文由李秉骏(@CashLee李秉骏)投稿于伯乐在线,也欢迎其他朋友投稿。提示:投稿时记得留下微博账号哦 ag真人 1

前段时间做过两次关于Phonegap的现场交流会议分享。基本上把Phonegap的一些特性和大家交流了一下,大家对于Phonegap的 兴趣也是非常多的。但是因为Phonegap相对于原生应用来说,只有一个View,这个View就是一个Web的容器,这使得Phonegap就存在很 多限制。其中一部分的限制我们已经通过HTML5的API以及Phonegap为我们搭建的桥去实现了,另外一部分我们就得通过Phonegap plugins来实现,而实际上我个人认为Phonegap最强大的地方也在于有那么大的一个群体在为他提供各种各样的Plugins,以便去应对实际项 目中遇到的问题。

我记得在和大家交流的时候大家经常会问Phonegap如何做本地的缓存啊(WebSQL),如何贴近原生应用(这个涉及到架构,界面渲染问题,这 里我也不好深入讲,毕竟不是本文要讨论的内容),还有一个很头疼的问题就是如果要做一个开放平台的应用,如何实现oAuth认证。此前我也遇到过类似的一 些情况,当我再次遇到这个棘手的问题的时候,我相信一定也有Phonegap的粉丝遇到类似的情况的。于是我就总结下来何大家探讨一下如何解决这个问题 吧。

首先目标:解决oAuth认证。

制定计划:1. 知道oAuth原理;2.了解Phonegap在处理这个问题时候的运行机制;3. 制定计划实现代码。

下面我们就来一步一步地分析,看如何解决这个情况吧。(因为我在项目中遇到的是腾讯微博开放平台的oAuth认证,那么下面我就用腾讯oAuth认证为例吧)

关于oAuth认证,相信做过开放平台应用的朋友都已经非常熟悉了,如果你还没有做过或者对于oAuth认证流程非常不了解,那么我建议你先了解一 下原理,在这里我不希望花太多的篇幅去介绍这个东西,因为在很多地方都可以找到,下面我推荐两个地址方便大家去阅读,一定要阅读,这会对你理解下面的文章 有莫大的帮助的。

腾讯微博开放平台:

新浪微博开放平台:

当然在这里上面需要阐述说明的是oAuth认证机制是一个通用的手法,但是因为每个开放平台有自己的政策,因此可能在其中稍有改变,而且最终获得的权限也会各不相同。而最近新浪微博实在太多坑爹的事情了,实在忍受不了,于是我转战到腾讯的平台了。

好的,如果你看完了oAuth认证的流程,就直接到这里来。众所周知,在oAuth认证的流程中,有一个授权页面,而这个授权页面是通过开放平台提供的,具体的样式见下图:

ag真人 2

这个页面用于输入开放平台的帐户以及密码,通过授权获取响应的openid以及openkey,最终换取access-token(待会我会结合腾讯微博oAuth认证流程的特点,以及代码和大家分析的)。

这个页面是弹出的,如果在Phonegap里面做的话会很奇怪:1,因为属于弹窗,在Phonegap中本身就是一个WebView如果你还弹的话 就会飞到了Safari的浏览器中,这就跳出应用本身,跳出去认证还有戏吗?2,通过iFrame,首先体验非常不好,其次iFrame本身又属于跨域的 问题,这就不好解决了(为什么体验不好呢,主要是因为授权页面的样式是不固定的,类似腾讯微博开放平台,就比新浪的授权页面做得差,根本不和手机匹配的, 而且有些做得好的,认证页宽度就是320px,就占了你整个应用的版面,体验很不好)那么Phonegap中该如何实现呢?

带着问题,我们就希望在Phonegap中再度引入一个WebView。刚刚提到Phonegap的强大还在于很多人以及官方的团队,为其提供了一 套很好的插件机制,以解决各种各样的需要。在Phonegap中有一个插件叫做ChildBrowser,顾名思义就是:子浏览器。(其实我在上两次的 Phonegap专题技术分享中以及提及到让大家用这个东西去解决,不过当时分享时间有限只能够草率带过,抱歉)子浏览器的作用其实就是让你在 Phonegap应用内部调起一个浏览器的View,让你进行pdf,图片,视频,甚至网页阅读的工具。(实际上你看我上面的截图,就是用 ChildBrowser来实现的)这就好了,这就可以让你调起浏览器而且不跳出应用本身了,可以很好地解决oAuth认证的问题。 ChildBrowser下载地址:

在地址上面,你应该已经看到ChildBrowser的安装方法以及使用方法了,非常简单,真正的即插即用。如果你觉得英文太难,这我就帮不了你 了,你就自行Google翻译一下吧。相信你很快就可以做出一个ChildBrowser的Demo的。在这个地址上面,其实你返回上一层目录,其实你也 已经看到各式各样的Phonegap Plugins,通过这些东西,你还可以调用起手机内部更多有趣的资源的!这个就要靠你自己去发掘啦!(其他平台的应用也有相应的插件的Android开 发者不要骂果粉哦!)

好了慢慢地我们就要涉及到代码部分了。首先我们看看调用ChildBrowser的Javascript代码:

JavaScript

cb = window.plugins.childBrowser; /* if(cb != null) { cb.onLocationChange = function(loc){ root.locChanged(loc); };//地址发生改变时候执行的函数 cb.onClose = function(){root.onCloseBrowser(); };//通过js关闭ChildBrowser的办法 cb.onOpenExternal = function(){root.onOpenExternal(); }; */ cb.showWebPage("");

1
2
3
4
5
6
7
8
        cb = window.plugins.childBrowser;
/*
        if(cb != null) {
        cb.onLocationChange = function(loc){ root.locChanged(loc); };//地址发生改变时候执行的函数
        cb.onClose = function(){root.onCloseBrowser(); };//通过js关闭ChildBrowser的办法
        cb.onOpenExternal = function(){root.onOpenExternal(); };
*/
        cb.showWebPage("http://google.com");

其中cb就是初始化的ChildBrowser,而showWebPage就是调起这个页面的方法。可见代码中要打开的网址就是 Google.com啦,这个地球人都能够看得懂了。于是我们就可以马上想到我们要用ChildBrowser打开的网址是我们在网上指定的应用授权站点 了。而我是部署在SAE上面的,所以下面的例子也用PHP来说吧,期待语言也是相同的道理,转义就可以了。在说代码之前,我们先来说说具体通讯的流程,以 及我们接下来要达到的目标。

ag真人 3
在这里,我们的手机端是通过访问SAE服务器,由SAE服务器管理数据并与腾讯微博开放平台通讯的,这里手机端并没有直接和腾讯微博开放平台通讯(我这样 处理的原因是1,方便在服务器端管理帐户,这样的话可以观察自己的应用的帐户状况;2,服务器端实现推送机制,方便管理token以及做api;3,服务 器端还可以和其他开放平台帐户绑定)。因此,我们的整套认证方案会在服务器端完成。

而根据腾讯微博开放平台,我们首先会在开放平台上面注册自己的应用,注册的流程以及办法我不说了,注册的地址是:,注册你的应用后,你相应能够获得的东西是:

JavaScript

应用名称:mobile_test_api 应用类型:客户端应用 App Key:88888888 App Secret:ainidenideiienfeomeomroemrome

1
2
3
4
应用名称:mobile_test_api
应用类型:客户端应用
App Key:88888888
App Secret:ainidenideiienfeomeomroemrome

在这里我的App key以及App Secret是假的(你懂的,你应该有你自己的),下面我们就使用腾讯提供给我们的PHP SDK,下载地址:。有了SDK后我们就可以把SDK放到自己的环境上面,然后配置服务器端的代码了。下图是我简单配置的服务端的代码,lib下存放的就是腾讯微博的sdk。当然实际生产环境和这个有不同。这里仅仅作为演示使用:

ag真人 4

ag真人,下面就根据腾讯微博认证的流程,逐一讲解一下这些文件以及内部的代码吧。

index.php

PHP

<?php require_once 'app_config.php'; $url=" header('Location:'.$url);

1
2
3
4
5
6
<?php
require_once 'app_config.php';
 
$url="https://open.t.qq.com/cgi-bin/oauth2/authorize?client_id=".$client_id."&APP_KEY=".$app_key."&wap=2&response_type=code&redirect_uri=http://yoururl.com/get_auth.php";//指定URL地址
 
header('Location:'.$url);

这里引入的app_config.php

PHP

<?php $client_id = '8888888888'; $app_key = 'anienineiienrieireowq2839289';

1
2
3
4
5
<?php
 
$client_id = '8888888888';
 
$app_key = 'anienineiienrieireowq2839289';

因为根据腾讯微博开放平台,我们第一步要获取的是Code,如下所述,我们要做的就是做好配置,获取这个Code

JavaScript

第一步:请求code 请求方法: GET 请求地址: 返回结果: 如果授权成功,授权服务器会将用户的浏览器重定向到redirect_uri,并带上code,openid和openkey等参数,重定向的url如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
第一步:请求code
 
请求方法:
GET
 
请求地址:
 
https://open.t.qq.com/cgi-bin/oauth2/authorize?client_id=APP_KEY&amp;response_type=code&amp;redirect_uri=http://www.myurl.com/example
 
返回结果:
如果授权成功,授权服务器会将用户的浏览器重定向到redirect_uri,并带上code,openid和openkey等参数,重定向的url如下:
 
http://www.myurl.com/example?code=CODE&amp;openid=OPENID&amp;openkey=OPENKEY

具体需要请求附带的参数,必须要按照oAuth2.0鉴权的页面提示的进行。()

然后我们再来看看我们所配置的文件:

get_auth.php

PHP

<?php require_once 'app_config.php'; $code = $_REQUEST['code']; $openid = $_REQUEST['openid']; $openkey = $_REQUEST['openkey']; $url = ""; $message = file_get_contents($url); /* success to print the access token message */ $access = explode("=",$message); print_r("<br />"); $access_message = explode("&",$access[1]); $access_token = $access_message[0]; $user_name = $access[4]; print_r($access_token ." " . $user_name);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
 
require_once 'app_config.php';
 
$code = $_REQUEST['code'];
 
$openid = $_REQUEST['openid'];
 
$openkey = $_REQUEST['openkey'];
 
$url = "https://open.t.qq.com/cgi-bin/oauth2/access_token?client_id=".$client_id."&client_secret=".$app_key."&grant_type=authorization_code&code=".$code."&redirect_uri=http://yoururl.com/get_auth.php";
 
$message = file_get_contents($url);
 
/* success to print the access token message */
 
$access = explode("=",$message);
 
print_r("<br />");
 
$access_message = explode("&",$access[1]);
 
$access_token = $access_message[0];
 
$user_name = $access[4];
 
print_r($access_token ."   " . $user_name);

其实到以上为止,我们的配置文件已经弄好了。在这个配置文件中,实际上我们要做的就是腾讯微博开放平台中提及的第二步:

JavaScript

第二步:请求accesstoken 请求地址: 返回结果: 返回字符串: access_token=ACCESS_TOKEN&expires_in=60&refresh_token=REFRESH_TOKEN

1
2
3
4
5
6
7
8
9
第二步:请求accesstoken
 
请求地址:
 
https://open.t.qq.com/cgi-bin/oauth2/access_token?client_id=APP_KEY&amp;client_secret=APP_SECRET&amp;redirect_uri=http://www.myurl.com/example&amp;grant_type=authorization_code&amp;code=CODE
 
返回结果:
返回字符串:
access_token=ACCESS_TOKEN&amp;expires_in=60&amp;refresh_token=REFRESH_TOKEN

如果你现在已经配置好你的服务端口,已经配置好手机端的ChildBrowser,你就已经可以在手机上面看看整个认证的流程了。现在的工作已经完 成了大部分了,不过细心的朋友可能会发现,对啊,认证是完成了,手机上还是没有获得授权啊,因为授权后的信息还不能够通过手机去获取。不要 急,ChildBrowser有趣的地方还没有完呢。在手机端上面我们完成了oAuth认证,总有一些参数返回,不管accesstoken是否存在手机 端,你总得有个帐户机制和服务端通讯。我的服务端在SAE上面,我就建立一个唯一id给手机,于是我就建立了一个帐户机制,存在服务端上,服务端上存储的东西是:

MySQL

CREATE TABLE IF NOT EXISTS `auth_user` ( `id` int(10) NOT NULL AUTO_INCREMENT, `muser` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `openkey` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

1
2
3
4
5
6
7
8
9
10
CREATE TABLE IF NOT EXISTS `auth_user` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `muser` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `openkey` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

其实这个表也还没有完善,我必须还要纪录这个用户是否在线(如果有推送机制)。此后手机端和服务端通讯就通过上面的id以及token等的信息进行 通讯,再通过服务端想腾讯微博进行api的通讯,获取我们想要的信息。那么认证后我们通过什么途径拿到认证后返回的信息呢?大家看看上面JS控制 ChildBrowser的代码。会发现里面有一个方法:

JavaScript

cb.onLocationChange = function (loc){ console.warn(loc); };

1
cb.onLocationChange = function (loc){ console.warn(loc); };

如果你在xCode上面跑这段代码的话,你会发现loc打出来的是每次ChildBrowser里面浏览的网页改变的地址。这个时候我们就可以顺水 推舟,根据这里提供的办法,用url的方式把地址返回到Phonegap负责逻辑处理的JS代码中,同时将相关需要通讯的信息也返回。返回后还可以通过回 调的方式执行关闭ChildBrowser的代码:

JavaScript

cb.close();

1
cb.close();

当然,你还可以执行更多异步请求的代码。至于说还可以通过怎么样的方式进行通讯其实还有很多办法,我这里仅仅是提供一下思路引导以及方法。具体的 话,还要实践出真理论,做到非常安全的通讯还值得我们继续深入探讨。那么我要介绍的大概就到这里为止。因为实际项目中我们还有push notification的机制,所以此后我应该还会联同@Jeff_Kit 实现一下Phonegap的推送方案,并整理出sdk,成文后开放出来方便大家交流。

对于本文如果有什么疑问或者建议都可以直接向我反馈,我的新浪微博是:@CashLee李秉骏 ,我还经常分享一些代码片段在github上面(开源的精力不多,所以开源项目较少,希望日后增加吧。)我的Github账号, 欢迎您和我随时进行交流,也希望Phonegap的中国开发者社区会变得越来越精彩。

注意:ChildBrowser控件在实际环境中因为安全问题可能需要修改,通讯过程中参数也建议加密。:-)

 

本文由李秉骏(@CashLee李秉骏)投稿于伯乐在线,也欢迎其他朋友投稿。提示:投稿时记得留下微博账号哦 ag真人 5

【如需转载,请标注并保留原文链接和作者等信息,谢谢合作!】

 

 

1 赞 收藏 2 评论

ag真人 6

继承的实现方式及原型概述

2015/07/15 · JavaScript · 原型, 继承

原文出处: 名一的博客   

对于 OO 语言,有一句话叫“Everything is object”,虽然 JavaScript 不是严格意义上的面向对象语言,但如果想要理解 JS 中的继承,这句话必须时刻铭记于心。

JS 的语法非常灵活,所以有人觉得它简单,因为怎么写都是对的;也有人觉得它难,因为很难解释某些语法的设计,谁能告诉我为什么 typeof null 是 object 而 typeof undefined 是 undefined 吗?并且这是在 null == undefined 的前提下。很多我们自认为“懂”了的知识点,细细琢磨起来,还是会发现有很多盲点,“无畏源于无知”吧……

前端基础进阶(10):面向对象实战之封装拖拽对象

2017/04/02 · JavaScript · 面向对象

原文出处: 波同学   

ag真人 7

终于

前面几篇文章,我跟大家分享了JavaScript的一些基础知识,这篇文章,将会进入第一个实战环节:利用前面几章的所涉及到的知识,封装一个拖拽对象。为了能够帮助大家了解更多的方式与进行对比,我会使用三种不同的方式来实现拖拽。

  • 不封装对象直接实现;
  • 利用原生JavaScript封装拖拽对象;
  • 通过扩展jQuery来实现拖拽对象。

本文的例子会放置于codepen.io中,供大家在阅读时直接查看。如果对于codepen不了解的同学,可以花点时间稍微了解一下。

拖拽的实现过程会涉及到非常多的实用小知识,因此为了巩固我自己的知识积累,也为了大家能够学到更多的知识,我会尽量详细的将一些细节分享出来,相信大家认真阅读之后,一定能学到一些东西。

1. 简单对象

既然是讲继承,自然是从最简单的对象说起:

JavaScript

var dog = { name: 'tom' }

1
2
3
var dog = {
  name: 'tom'
}

这便是对象直接量了。每一个对象直接量都是 Object 的子类,即

JavaScript

dog instanceof Object; // true

1
dog instanceof Object; // true
1、如何让一个DOM元素动起来

我们常常会通过修改元素的top,left,translate来其的位置发生改变。在下面的例子中,每点击一次按钮,对应的元素就会移动5px。大家可点击查看。

点击查看一个让元素动起来的小例子

由于修改一个元素top/left值会引起页面重绘,而translate不会,因此从性能优化上来判断,我们会优先使用translate属性。

2. 构造函数

JS 中的构造函数与普通函数并没有什么两样,只不过在调用时,前面加上了 new 关键字,就当成是构造函数了。

JavaScript

function Dog(name) { this.name = name; } var dog = new Dog('tom'); dog instanceof Dog; // true

1
2
3
4
5
6
7
function Dog(name) {
  this.name = name;
}
 
var dog = new Dog('tom');
 
dog instanceof Dog; // true

两个问题,第一,不加 new 关键字有什么后果?

那么 Dog 函数中的 this 在上下文(Context)中被解释为全局变量,具体在浏览器端的话是 window 对象,在 node 环境下是一个 global 对象。

第二,dog 的值是什么?很简单,undefined 。Dog 函数没有返回任何值,执行结束后,dog 的值自然是 undefined 。

关于 new 的过程,这里也顺便介绍一下,这个对后面理解原型(prototype)有很大的帮助:

  1. 创建一个空的对象,仅包含 Object 的属性和方法。
  2. 将 prototype 中的属性和方法创建一份引用,赋给新对象。
  3. 将 this 上的属性和方法新建一份,赋给新对象。
  4. 返回 this 对象,忽略 return 语句。

需要明确的是,prototype 上的属性和方法是实例间共享的,this 上的属性和方法是每个实例独有的。

2、如何获取当前浏览器支持的transform兼容写法

transform是css3的属性,当我们使用它时就不得不面对兼容性的问题。不同版本浏览器的兼容写法大致有如下几种:

['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform']

因此我们需要判断当前浏览器环境支持的transform属性是哪一种,方法如下:

JavaScript

// 获取当前浏览器支持的transform兼容写法 function getTransform() { var transform = '', divStyle = document.createElement('div').style, // 可能涉及到的几种兼容性写法,通过循环找出浏览器识别的那一个 transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'], i = 0, len = transformArr.length; for(; i < len; i++) { if(transformArr[i] in divStyle) { // 找到之后立即返回,结束函数 return transform = transformArr[i]; } } // 如果没有找到,就直接返回空字符串 return transform; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 获取当前浏览器支持的transform兼容写法
function getTransform() {
    var transform = '',
        divStyle = document.createElement('div').style,
        // 可能涉及到的几种兼容性写法,通过循环找出浏览器识别的那一个
        transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'],
 
        i = 0,
        len = transformArr.length;
 
    for(; i < len; i++)  {
        if(transformArr[i] in divStyle) {
            // 找到之后立即返回,结束函数
            return transform = transformArr[i];
        }
    }
 
    // 如果没有找到,就直接返回空字符串
    return transform;
}

该方法用于获取浏览器支持的transform属性。如果返回的为空字符串,则表示当前浏览器并不支持transform,这个时候我们就需要使用left,top值来改变元素的位置。如果支持,就改变transform的值。

3. 引入 prototype

现在为 Dog 函数加上 prototype,看一个例子:

JavaScript

function Dog(name) { this.name = name; this.bark = function() {}; } Dog.prototype.jump = function() {}; Dog.prototype.species = 'Labrador'; Dog.prototype.teeth = ['1', '2', '3', '4']; var dog1 = new Dog('tom'), dog2 = new Dog('jerry'); dog1.bark !== dog2.bark; // true dog1.jump === dog2.jump; // true dog1.teeth.push('5'); dog2.teeth; // ['1', '2', '3', '4', '5']

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Dog(name) {
  this.name = name;
  this.bark = function() {};
}
 
Dog.prototype.jump = function() {};
Dog.prototype.species = 'Labrador';
Dog.prototype.teeth = ['1', '2', '3', '4'];
 
var dog1 = new Dog('tom'),
    dog2 = new Dog('jerry');
 
dog1.bark !== dog2.bark; // true
dog1.jump === dog2.jump; // true
 
dog1.teeth.push('5');
dog2.teeth; // ['1', '2', '3', '4', '5']

看到有注释的那三行应该可以明白“引用”和“新建”的区别了。

那么我们经常说到的“原型链”到底是什么呢?这个术语出现在继承当中,它用于表示对象实例中的属性和方法来自于何处(哪个父类)。好吧,这是笔者的解释。

JavaScript

- Object bark: Dog/this.bark() name: 'tom' - __proto__: Object jump: Dog.prototype.jump() species: 'Labrador' + teeth: Array[4] + constructor: Dog() + __proto__: Object

1
2
3
4
5
6
7
8
9
- Object
  bark: Dog/this.bark()
  name: 'tom'
- __proto__: Object
    jump: Dog.prototype.jump()
    species: 'Labrador'
  + teeth: Array[4]
  + constructor: Dog()
  + __proto__: Object  

上面的是 dog1 的原型链,不知道够不够直观地描述“链”这个概念。

  1. 其中,bark 和 name 是定义在 this 中的,所以最顶层可以看到它俩。
  2. 然后,每一个对象都会有一个 __proto__ 属性(IE 11+),它表示定义在原型上的属性和方法,所以 jump、species 和 teeth 自然就在这儿了。
  3. 最后就一直向上找 __proto__ 中的属性和方法。

  4. 继承的几种实现


3、 如何获取元素的初始位置

我们首先需要获取到目标元素的初始位置,因此这里我们需要一个专门用来获取元素样式的功能函数。

但是获取元素样式在IE浏览器与其他浏览器有一些不同,因此我们需要一个兼容性的写法。

JavaScript

function getStyle(elem, property) { // ie通过currentStyle来获取元素的样式,其他浏览器通过getComputedStyle来获取 return document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(elem, false)[property] : elem.currentStyle[property]; }

1
2
3
4
function getStyle(elem, property) {
    // ie通过currentStyle来获取元素的样式,其他浏览器通过getComputedStyle来获取
    return document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(elem, false)[property] : elem.currentStyle[property];
}

有了这个方法之后,就可以开始动手写获取目标元素初始位置的方法了。

JavaScript

function getTargetPos(elem) { var pos = {x: 0, y: 0}; var transform = getTransform(); if(transform) { var transformValue = getStyle(elem, transform); if(transformValue == 'none') { elem.style[transform] = 'translate(0, 0)'; return pos; } else { var temp = transformValue.match(/-?d+/g); return pos = { x: parseInt(temp[4].trim()), y: parseInt(temp[5].trim()) } } } else { if(getStyle(elem, 'position') == 'static') { elem.style.position = 'relative'; return pos; } else { var x = parseInt(getStyle(elem, 'left') ? getStyle(elem, 'left') : 0); var y = parseInt(getStyle(elem, 'top') ? getStyle(elem, 'top') : 0); return pos = { x: x, y: y } } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function getTargetPos(elem) {
    var pos = {x: 0, y: 0};
    var transform = getTransform();
    if(transform) {
        var transformValue = getStyle(elem, transform);
        if(transformValue == 'none') {
            elem.style[transform] = 'translate(0, 0)';
            return pos;
        } else {
            var temp = transformValue.match(/-?d+/g);
            return pos = {
                x: parseInt(temp[4].trim()),
                y: parseInt(temp[5].trim())
            }
        }
    } else {
        if(getStyle(elem, 'position') == 'static') {
            elem.style.position = 'relative';
            return pos;
        } else {
            var x = parseInt(getStyle(elem, 'left') ? getStyle(elem, 'left') : 0);
            var y = parseInt(getStyle(elem, 'top') ? getStyle(elem, 'top') : 0);
            return pos = {
                x: x,
                y: y
            }
        }
    }
}

在拖拽过程中,我们需要不停的设置目标元素的新位置,这样它才会移动起来,因此我们需要一个设置目标元素位置的方法。

JavaScript

// pos = { x: 200, y: 100 } function setTargetPos(elem, pos) { var transform = getTransform(); if(transform) { elem.style[transform] = 'translate('+ pos.x +'px, '+ pos.y +'px)'; } else { elem.style.left = pos.x + 'px'; elem.style.top = pos.y + 'px'; } return elem; }

1
2
3
4
5
6
7
8
9
10
11
// pos = { x: 200, y: 100 }
function setTargetPos(elem, pos) {
    var transform = getTransform();
    if(transform) {
        elem.style[transform] = 'translate('+ pos.x +'px, '+ pos.y +'px)';
    } else {
        elem.style.left = pos.x + 'px';
        elem.style.top = pos.y + 'px';
    }
    return elem;
}

版权声明:本文由ag真人发布于人才招聘,转载请注明出处:前端基础进阶,继承的实现方式及原型概述