Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
CoCo_Code_Op2
next.js
提交
e2ab55ad
N
next.js
项目概览
CoCo_Code_Op2
/
next.js
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
N
next.js
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
e2ab55ad
编写于
10月 08, 2016
作者:
N
nkzawa
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix client/router
上级
89f96cc1
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
156 addition
and
166 deletion
+156
-166
client/next.js
client/next.js
+1
-1
client/router.js
client/router.js
+136
-147
lib/app.js
lib/app.js
+8
-5
lib/link.js
lib/link.js
+10
-12
server/render.js
server/render.js
+1
-1
未找到文件。
client/next.js
浏览文件 @
e2ab55ad
...
@@ -12,7 +12,7 @@ const {
...
@@ -12,7 +12,7 @@ const {
const
App
=
app
?
evalScript
(
app
).
default
:
DefaultApp
const
App
=
app
?
evalScript
(
app
).
default
:
DefaultApp
const
Component
=
evalScript
(
component
).
default
const
Component
=
evalScript
(
component
).
default
const
router
=
new
Router
({
Component
,
props
})
const
router
=
new
Router
({
Component
})
const
headManager
=
new
HeadManager
()
const
headManager
=
new
HeadManager
()
const
container
=
document
.
getElementById
(
'
__next
'
)
const
container
=
document
.
getElementById
(
'
__next
'
)
const
appProps
=
{
Component
,
props
,
router
,
headManager
}
const
appProps
=
{
Component
,
props
,
router
,
headManager
}
...
...
client/router.js
浏览文件 @
e2ab55ad
...
@@ -4,119 +4,105 @@ import shallowEquals from './shallow-equals'
...
@@ -4,119 +4,105 @@ import shallowEquals from './shallow-equals'
export
default
class
Router
{
export
default
class
Router
{
constructor
(
initialData
)
{
constructor
(
initialData
)
{
this
.
subscriptions
=
[]
// represents the current component key
this
.
route
=
toRoute
(
location
.
pathname
)
const
id
=
createUid
()
const
route
=
toRoute
(
location
.
pathname
)
this
.
currentRoute
=
route
this
.
currentComponentData
=
{
...
initialData
,
id
}
// set up the component cache (by route keys)
// set up the component cache (by route keys)
this
.
components
=
{
[
route
]:
initialData
}
this
.
components
=
{
[
this
.
route
]:
initialData
}
// in order for `e.state` to work on the `onpopstate` event
// we have to register the initial route upon initialization
this
.
replace
(
id
,
getURL
())
this
.
subscriptions
=
new
Set
()
this
.
componentLoadCancel
=
null
this
.
onPopState
=
this
.
onPopState
.
bind
(
this
)
this
.
onPopState
=
this
.
onPopState
.
bind
(
this
)
window
.
addEventListener
(
'
unload
'
,
()
=>
{})
window
.
addEventListener
(
'
popstate
'
,
this
.
onPopState
)
window
.
addEventListener
(
'
popstate
'
,
this
.
onPopState
)
}
}
onPopState
(
e
)
{
onPopState
(
e
)
{
this
.
abortComponentLoad
()
this
.
abortComponentLoad
()
const
cur
=
this
.
currentComponentData
.
id
const
url
=
getURL
()
const
route
=
(
e
.
state
||
{}).
route
||
toRoute
(
location
.
pathname
)
const
{
fromComponent
,
route
}
=
e
.
state
||
{}
if
(
fromComponent
&&
cur
&&
fromComponent
===
cur
)
{
Promise
.
resolve
()
// if the component has not changed due
.
then
(
async
()
=>
{
// to the url change, it means we only
const
data
=
await
this
.
fetchComponent
(
route
)
// need to notify the subscriber about
let
props
// the URL change
if
(
route
!==
this
.
route
)
{
this
.
set
(
url
)
props
=
await
this
.
getInitialProps
(
data
.
Component
)
}
else
{
}
this
.
fetchComponent
(
route
||
url
,
(
err
,
data
)
=>
{
if
(
err
)
{
this
.
route
=
route
this
.
set
(
getURL
(),
{
...
data
,
props
})
})
.
catch
((
err
)
=>
{
if
(
err
.
cancelled
)
return
// the only way we can appropriately handle
// the only way we can appropriately handle
// this failure is deferring to the browser
// this failure is deferring to the browser
// since the URL has already changed
// since the URL has already changed
location
.
reload
()
location
.
reload
()
}
else
{
this
.
currentRoute
=
route
||
toRoute
(
location
.
pathname
)
this
.
currentComponentData
=
data
this
.
set
(
url
)
}
})
})
}
}
}
update
(
route
,
data
)
{
async
update
(
route
,
data
)
{
data
.
Component
=
evalScript
(
data
.
component
).
default
data
.
Component
=
evalScript
(
data
.
component
).
default
delete
data
.
component
delete
data
.
component
this
.
components
[
route
]
=
data
this
.
components
[
route
]
=
data
if
(
route
===
this
.
currentRoute
)
{
let
cancelled
=
false
if
(
route
===
this
.
route
)
{
const
cancel
=
()
=>
{
cancelled
=
true
}
let
props
this
.
componentLoadCancel
=
cancel
try
{
getInitialProps
(
data
,
(
err
,
dataWithProps
)
=>
{
props
=
await
this
.
getInitialProps
(
data
.
Component
)
if
(
cancel
===
this
.
componentLoadCancel
)
{
}
catch
(
err
)
{
this
.
componentLoadCancel
=
false
if
(
err
.
cancelled
)
return
false
}
throw
err
if
(
cancelled
)
return
if
(
err
)
throw
err
this
.
currentComponentData
=
dataWithProps
this
.
notify
()
})
}
}
this
.
notify
({
...
data
,
props
})
}
}
return
true
goTo
(
url
,
fn
)
{
this
.
change
(
'
pushState
'
,
null
,
url
,
fn
)
}
}
back
()
{
back
()
{
history
.
back
()
history
.
back
()
}
}
push
(
fromComponent
,
url
,
fn
)
{
push
(
route
,
url
)
{
this
.
change
(
'
pushState
'
,
fromComponent
,
url
,
fn
)
return
this
.
change
(
'
pushState
'
,
route
,
url
)
}
}
replace
(
id
,
url
,
fn
)
{
replace
(
route
,
url
)
{
this
.
change
(
'
replaceState
'
,
id
,
url
,
fn
)
return
this
.
change
(
'
replaceState
'
,
route
,
url
)
}
}
change
(
method
,
id
,
url
,
fn
)
{
async
change
(
method
,
route
,
url
)
{
this
.
abortComponentLoad
(
)
if
(
!
route
)
route
=
toRoute
(
parse
(
url
).
pathname
)
const
set
=
(
id
)
=>
{
this
.
abortComponentLoad
()
const
state
=
id
?
{
fromComponent
:
id
,
route
:
this
.
currentRoute
}
:
{}
history
[
method
](
state
,
null
,
url
)
this
.
set
(
url
)
if
(
fn
)
fn
(
null
)
}
if
(
this
.
currentComponentData
&&
id
!==
this
.
currentComponentData
.
id
)
{
let
data
this
.
fetchComponent
(
url
,
(
err
,
data
)
=>
{
let
props
if
(
!
err
)
{
try
{
this
.
currentRoute
=
toRoute
(
url
)
data
=
await
this
.
fetchComponent
(
route
)
this
.
currentComponentData
=
data
if
(
route
!==
this
.
route
)
{
set
(
data
.
id
)
props
=
await
this
.
getInitialProps
(
data
.
Component
)
}
}
if
(
fn
)
fn
(
err
,
data
)
}
catch
(
err
)
{
})
if
(
err
.
cancelled
)
return
false
}
else
{
throw
err
set
(
id
)
}
}
history
[
method
]({
route
},
null
,
url
)
this
.
route
=
route
this
.
set
(
url
,
{
...
data
,
props
})
return
true
}
}
set
(
url
)
{
set
(
url
,
data
)
{
const
parsed
=
parse
(
url
,
true
)
const
parsed
=
parse
(
url
,
true
)
if
(
this
.
urlIsNew
(
parsed
))
{
if
(
this
.
urlIsNew
(
parsed
))
{
this
.
pathname
=
parsed
.
pathname
this
.
pathname
=
parsed
.
pathname
this
.
query
=
parsed
.
query
this
.
query
=
parsed
.
query
this
.
notify
()
this
.
notify
(
data
)
}
}
}
}
...
@@ -124,52 +110,66 @@ export default class Router {
...
@@ -124,52 +110,66 @@ export default class Router {
return
this
.
pathname
!==
pathname
||
!
shallowEquals
(
query
,
this
.
query
)
return
this
.
pathname
!==
pathname
||
!
shallowEquals
(
query
,
this
.
query
)
}
}
fetchComponent
(
url
,
fn
)
{
async
fetchComponent
(
url
)
{
const
{
pathname
}
=
parse
(
url
)
const
route
=
toRoute
(
parse
(
url
).
pathname
)
const
route
=
toRoute
(
pathname
)
let
data
=
this
.
components
[
route
]
if
(
data
)
return
data
let
cancel
let
cancelled
=
false
let
cancelled
=
false
let
componentXHR
=
null
const
cancel
=
()
=>
{
const
componentUrl
=
toJSONUrl
(
route
)
data
=
await
new
Promise
((
resolve
,
reject
)
=>
{
this
.
componentLoadCancel
=
cancel
=
()
=>
{
cancelled
=
true
cancelled
=
true
if
(
componentXHR
.
abort
)
componentXHR
.
abort
()
if
(
componentXHR
&&
componentXHR
.
abort
)
{
const
err
=
new
Error
(
'
Cancelled
'
)
componentXHR
.
abort
()
err
.
cancelled
=
true
}
reject
(
err
)
}
}
if
(
this
.
components
[
route
])
{
const
componentXHR
=
loadComponent
(
componentUrl
,
(
err
,
data
)
=>
{
const
data
=
this
.
components
[
route
]
if
(
err
)
return
reject
(
err
)
getInitialProps
(
data
,
(
err
,
dataWithProps
)
=>
{
resolve
(
data
)
if
(
cancel
===
this
.
componentLoadCancel
)
{
})
this
.
componentLoadCancel
=
false
}
if
(
cancelled
)
return
fn
(
err
,
dataWithProps
)
})
})
this
.
componentLoadCancel
=
cancel
return
}
const
componentUrl
=
toJSONUrl
(
route
)
componentXHR
=
loadComponent
(
componentUrl
,
(
err
,
data
)
=>
{
if
(
cancel
===
this
.
componentLoadCancel
)
{
if
(
cancel
===
this
.
componentLoadCancel
)
{
this
.
componentLoadCancel
=
false
this
.
componentLoadCancel
=
null
}
}
if
(
err
)
{
if
(
!
cancelled
)
fn
(
err
)
}
else
{
const
d
=
{
...
data
,
id
:
createUid
()
}
// we update the cache even if cancelled
// we update the cache even if cancelled
if
(
!
this
.
components
[
route
])
{
if
(
data
)
this
.
components
[
route
]
=
data
this
.
components
[
route
]
=
d
if
(
cancelled
)
{
const
err
=
new
Error
(
'
Cancelled
'
)
err
.
cancelled
=
true
throw
err
}
}
if
(
!
cancelled
)
fn
(
null
,
d
)
return
data
}
}
})
async
getInitialProps
(
Component
)
{
let
cancelled
=
false
const
cancel
=
()
=>
{
cancelled
=
true
}
this
.
componentLoadCancel
=
cancel
this
.
componentLoadCancel
=
cancel
const
props
=
await
(
Component
.
getInitialProps
?
Component
.
getInitialProps
({})
:
{})
if
(
cancel
===
this
.
componentLoadCancel
)
{
this
.
componentLoadCancel
=
null
}
if
(
cancelled
)
{
const
err
=
new
Error
(
'
Cancelled
'
)
err
.
cancelled
=
true
throw
err
}
return
props
}
}
abortComponentLoad
()
{
abortComponentLoad
()
{
...
@@ -179,44 +179,44 @@ export default class Router {
...
@@ -179,44 +179,44 @@ export default class Router {
}
}
}
}
notify
()
{
notify
(
data
)
{
this
.
subscriptions
.
forEach
(
fn
=>
fn
(
))
this
.
subscriptions
.
forEach
(
(
fn
)
=>
fn
(
data
))
}
}
subscribe
(
fn
)
{
subscribe
(
fn
)
{
this
.
subscriptions
.
push
(
fn
)
this
.
subscriptions
.
add
(
fn
)
return
()
=>
{
return
()
=>
this
.
subscriptions
.
delete
(
fn
)
const
i
=
this
.
subscriptions
.
indexOf
(
fn
)
if
(
~
i
)
this
.
subscriptions
.
splice
(
i
,
1
)
}
}
}
}
}
// every route finishing in `/test/` becomes `/test`
function
getURL
()
{
return
location
.
pathname
+
(
location
.
search
||
''
)
+
(
location
.
hash
||
''
)
}
export
function
toRoute
(
path
)
{
function
toRoute
(
path
)
{
return
path
.
replace
(
/
\/
$/
,
''
)
||
'
/
'
return
path
.
replace
(
/
\/
$/
,
''
)
||
'
/
'
}
}
export
function
toJSONUrl
(
route
)
{
function
toJSONUrl
(
route
)
{
return
(
'
/
'
===
route
?
'
/index
'
:
route
)
+
'
.json
'
return
(
'
/
'
===
route
?
'
/index
'
:
route
)
+
'
.json
'
}
}
export
function
loadComponent
(
url
,
fn
)
{
function
loadComponent
(
url
,
fn
)
{
return
loadJSON
(
url
,
(
err
,
data
)
=>
{
return
loadJSON
(
url
,
(
err
,
data
)
=>
{
if
(
err
&&
fn
)
fn
(
err
)
if
(
err
)
return
fn
(
err
)
const
{
component
,
props
}
=
data
const
Component
=
evalScript
(
component
).
default
getInitialProps
({
Component
,
props
},
fn
)
})
}
function
getURL
()
{
const
{
component
}
=
data
return
location
.
pathname
+
(
location
.
search
||
''
)
+
(
location
.
hash
||
''
)
}
function
createUid
()
{
let
module
return
Math
.
floor
(
Math
.
random
()
*
1
e16
)
try
{
module
=
evalScript
(
component
)
}
catch
(
err
)
{
return
fn
(
err
)
}
const
Component
=
module
.
default
||
module
fn
(
null
,
{
Component
})
})
}
}
function
loadJSON
(
url
,
fn
)
{
function
loadJSON
(
url
,
fn
)
{
...
@@ -234,21 +234,10 @@ function loadJSON (url, fn) {
...
@@ -234,21 +234,10 @@ function loadJSON (url, fn) {
fn
(
null
,
data
)
fn
(
null
,
data
)
}
}
xhr
.
onerror
=
()
=>
{
xhr
.
onerror
=
()
=>
{
if
(
fn
)
fn
(
new
Error
(
'
XHR failed. Status:
'
+
xhr
.
status
))
fn
(
new
Error
(
'
XHR failed. Status:
'
+
xhr
.
status
))
}
}
xhr
.
open
(
'
GET
'
,
url
)
xhr
.
open
(
'
GET
'
,
url
)
xhr
.
send
()
xhr
.
send
()
return
xhr
return
xhr
}
}
function
getInitialProps
(
data
,
fn
)
{
const
{
Component
:
{
getInitialProps
}
}
=
data
if
(
getInitialProps
)
{
Promise
.
resolve
(
getInitialProps
({}))
.
then
((
props
)
=>
fn
(
null
,
{
...
data
,
props
}))
.
catch
(
fn
)
}
else
{
fn
(
null
,
data
)
}
}
lib/app.js
浏览文件 @
e2ab55ad
...
@@ -24,9 +24,10 @@ export default class App extends Component {
...
@@ -24,9 +24,10 @@ export default class App extends Component {
componentDidMount
()
{
componentDidMount
()
{
const
{
router
}
=
this
.
props
const
{
router
}
=
this
.
props
this
.
close
=
router
.
subscribe
(()
=>
{
this
.
close
=
router
.
subscribe
((
data
)
=>
{
const
props
=
data
.
props
||
this
.
state
.
props
const
state
=
propsToState
({
const
state
=
propsToState
({
...
router
.
currentComponentD
ata
,
...
d
ata
,
router
router
})
})
...
@@ -55,13 +56,15 @@ export default class App extends Component {
...
@@ -55,13 +56,15 @@ export default class App extends Component {
function
propsToState
(
props
)
{
function
propsToState
(
props
)
{
const
{
Component
,
router
}
=
props
const
{
Component
,
router
}
=
props
const
{
route
}
=
router
const
url
=
{
const
url
=
{
query
:
router
.
query
,
query
:
router
.
query
,
pathname
:
router
.
pathname
,
pathname
:
router
.
pathname
,
back
:
()
=>
router
.
back
(),
back
:
()
=>
router
.
back
(),
goTo
:
(
url
,
fn
)
=>
router
.
goTo
(
url
,
fn
),
push
:
(
url
)
=>
router
.
push
(
route
,
url
),
push
:
(
url
,
fn
)
=>
router
.
push
(
Component
,
url
,
fn
),
pushTo
:
(
url
)
=>
router
.
push
(
null
,
url
),
replace
:
(
url
,
fn
)
=>
router
.
replace
(
Component
,
url
,
fn
)
replace
:
(
url
)
=>
router
.
replace
(
route
,
url
),
replaceTo
:
(
url
)
=>
router
.
replace
(
null
,
url
)
}
}
return
{
return
{
...
...
lib/link.js
浏览文件 @
e2ab55ad
...
@@ -27,15 +27,13 @@ export default class Link extends Component {
...
@@ -27,15 +27,13 @@ export default class Link extends Component {
e
.
preventDefault
()
e
.
preventDefault
()
// straight up redirect
// straight up redirect
this
.
context
.
router
.
goTo
(
href
,
(
err
)
=>
{
this
.
context
.
router
.
push
(
null
,
href
)
if
(
err
)
{
.
then
((
success
)
=>
{
if
(
!
success
)
return
if
(
false
!==
scroll
)
window
.
scrollTo
(
0
,
0
)
})
.
catch
((
err
)
=>
{
if
(
this
.
props
.
onError
)
this
.
props
.
onError
(
err
)
if
(
this
.
props
.
onError
)
this
.
props
.
onError
(
err
)
return
}
if
(
false
!==
scroll
)
{
window
.
scrollTo
(
0
,
0
)
}
})
})
}
}
...
@@ -45,15 +43,15 @@ export default class Link extends Component {
...
@@ -45,15 +43,15 @@ export default class Link extends Component {
onClick
:
this
.
linkClicked
onClick
:
this
.
linkClicked
}
}
const
is
Child
Anchor
=
child
&&
'
a
'
===
child
.
type
const
isAnchor
=
child
&&
'
a
'
===
child
.
type
// if child does not specify a href, specify it
// if child does not specify a href, specify it
// so that repetition is not needed by the user
// so that repetition is not needed by the user
if
(
!
is
Child
Anchor
||
!
(
'
href
'
in
child
.
props
))
{
if
(
!
isAnchor
||
!
(
'
href
'
in
child
.
props
))
{
props
.
href
=
this
.
props
.
href
props
.
href
=
this
.
props
.
href
}
}
if
(
is
Child
Anchor
)
{
if
(
isAnchor
)
{
return
React
.
cloneElement
(
child
,
props
)
return
React
.
cloneElement
(
child
,
props
)
}
else
{
}
else
{
return
<
a
{...
props
}
>
{
child
}
<
/a
>
return
<
a
{...
props
}
>
{
child
}
<
/a
>
...
...
server/render.js
浏览文件 @
e2ab55ad
...
@@ -35,7 +35,7 @@ export async function render (path, req, res, { dir = process.cwd(), dev = false
...
@@ -35,7 +35,7 @@ export async function render (path, req, res, { dir = process.cwd(), dev = false
html
,
html
,
head
,
head
,
css
,
css
,
data
:
{
component
},
data
:
{
component
,
props
},
hotReload
:
false
,
hotReload
:
false
,
dev
dev
})
})
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录