今天群里灰大出了个题:
function getRelativeURL(url, baseURL) {
// 获取url相对baseURL的相对路径
// url和baseURL都是绝对路径或都是相对路径的情况下,有可能计算出结果,否则扔Error
// 如果都是绝对路径,但不在同一个域、同一个协议、同一个端口下,即无法计算相对路径,扔Error
}
用了点时间写了一下:
function getRelativeURL ( url, baseUrl ) {
var path,
basePath,
i = 0,
compare = {},
r = { 'proto' : /(^[a-zA-Z]{1,4}):\/\/(.*)/,
'domain' : /(^[-_a-zA-Z.]+)((?:\/|:|$)?.*)/,
'port' : /(?:^:)(\d+)((?:\/|$).*)/,
'word' : /[^, ]+/g,
};
compare[ 'url' ] = parseUrl( url );
compare[ 'baseUrl' ] = parseUrl( baseUrl );
if ( different( 'proto' ) || different( 'domain' ) || different( 'port' ) ) return false; //协议、域名、端口不同
path = compare.url.path;
basePath = compare.baseUrl.path;
while ( path.length && path[ 0 ] == basePath[ 0 ] ) { //去除相同父目录
path.shift();
basePath.shift();
}
if ( path.length == 0 && basePath.length == 0 ) return './'; //两个url相同
if ( path.length == 0 ) return parent( basePath.length ); //baseUrl是url的子目录
if ( basePath.length == 0 ) return path.join( '/' ) + '/'; //url是baseUrl的子目录
return parent( basePath.length ) + path.join( '/' ) + '/'; //url和baseUrl互不包含
function different ( name ) {
return compare[ 'url' ][ name ] != compare[ 'baseUrl' ][ name ];
}
function notValidUrl () {
return compare[ 'url' ][ 'proto' ] == '' || compare[ 'baseUrl' ][ 'proto' ] == '';
}
function parseUrl ( url ) {
var parsed = {};
'proto,domain,port'.replace( r.word, function( name ){
var match, reg = r[ name ];
if ( !reg.test( url ) ) {
parsed[ name ] = '';
return;
}
match = url.match( reg );
url = match[ 2 ];
parsed[ name ] = match[ 1 ];
});
parsed[ 'path' ] = url.replace(/\/+$/,'').split('/');
return parsed;
}
function parent ( level ) {
console.log(level);
var result = [];
while ( level-- ) result.push( '../' );
return result.join('');
}
};
使用单元测试如下:
test("url和baseURL并非都是绝对路径或都是相对路径,没有结果", function() {
expect(4);
ok(!getRelativeURL('http://aoeu/ao','/aoeu'),'绝对,相对');
ok(!getRelativeURL('/aoeu','http://aoeu/ao'),'相对,绝对');
ok(getRelativeURL('http://aoeu','http://aoeu/ao'),'绝对,绝对');
ok(getRelativeURL('/aoeu','/ao'),'相对,相对');
});
test("不在同一个域、同一个协议、同一个端口下,没有结果", function() {
expect(3);
ok(!getRelativeURL('http://aoc.com','http://aoeu.com'),'不同域');
ok(!getRelativeURL('https://aoc.com','ftp://aoeu.com'),'不同协议');
ok(!getRelativeURL('https://aoc.com:88','ftp://aoc.com:89'),'不同端口');
});
test("是否以/结尾不影响结果",function() {
expect(3);
equal(getRelativeURL('http://aoeu.com/aoeu/','http://aoeu.com/'),getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com'),'都以/结尾');
equal(getRelativeURL('http://aoeu.com/aoeu/','http://aoeu.com'),getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com'),'url以/结尾');
equal(getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com/'),getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com'),'baseUrl以/结尾');
})
test("相同目录",function(){
expect(3);
equal(getRelativeURL('http://aoeu.com','http://aoeu.com/'),'./','根目录');
equal(getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com/aoeu'),'./','单级');
equal(getRelativeURL('http://aoeu.com/ao/eu','http://aoeu.com/ao/eu/'),'./','多级');
})
test("url和baseUrl中有一个为根目录",function() {
expect(4);
equal(getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com'),'aoeu/','url为baseUrl的单级子目录');
equal(getRelativeURL('http://aoeu.com/ao/eu','http://aoeu.com'),'ao/eu/','url为baseUrl的多级子目录');
equal(getRelativeURL('http://aoeu.com','http://aoeu.com/ao'),'../','baseUrl为url的单级子目录');
equal(getRelativeURL('http://aoeu.com','http://aoeu.com/ao/eu'),'../../','baseUrl为url的多级子目录');
!
})
test("其他",function() {
expect(2);
equal(getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com/ueoa'),'../aoeu/','单级');
equal(getRelativeURL('http://aoeu.com/ao/eu','http://aoeu.com/eu/ao'),'../../ao/eu/','多级');
})
如有更好解法或发现错误,请不吝赐教:)