今天群里灰大出了个题:
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/','多级'); })
如有更好解法或发现错误,请不吝赐教:)
老张,好久没来看你的博客,最近正好有这个需求。谢谢啦。