刷新页面时,启用 pushState 的 Backbone 路由不起作用

3

我有一个简单的路由器:

Erin.Router = Backbone.Router.extend({
    initialize: function() {
        Backbone.history.start({pushState: true});
    },
    routes: {
        '' : 'index',
        'project/:img' :'project',
    },
    index: function() {
        var galleryView = new Erin.GalleryView();
    },
    project: function(img) {
        console.log(img);
    }
}); 
< p > Erin.GalleryView的模板可能存在问题:
<script type="text/template" id="gallery-grid">
        <a href="/project/<%= id %>">
            <img src="<%= thumbnail %>" />
            <span class="desc">
                <div class="desc-wrap">
                    <p class="title"><%= title %></p>
                    <p class="client"><%= client %></p>
                </div>
            </span>
        </a>
    </script>
画廊视图和画廊项代码。
Erin.GalleryItem = Backbone.View.extend({
    tagName: 'div',
    className: 'project-container',
    //Grab the template html
    template: _.template($('#gallery-grid').html()),
    //Set up the render function
    render: function() {
        //What is the $el in this case?
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    }
});

Erin.GalleryView = Backbone.View.extend({
    el: '#projects',
    initialize: function() {
        //create new collection
        this.col = new Erin.Gallery();
        //Listen to all events on collection
        //Call Render on it
        this.listenTo(this.col,'all',this.render);
        //Fetch data
        this.col.fetch();
    },
    render: function() {
        //Get reference to the view object
        var that = this;
        //Empty div
        this.$el.empty();
        //For each model in the collection
        _.each(this.col.models, function(model){
            //call the renderItem method
            that.renderItem(model);
        },this);
    },
    renderItem: function(model) {
        //create a new single item view
        var itemView = new Erin.GalleryItem({
            model:model
        });
        //Append items to to element, in this case "#projects"
        this.$el.append(itemView.render().el);  
    }
});

然后我有一个准备好的文档。
$(function() {
    var router = new Erin.Router();
    $('#projects').on('click', 'a[href ^="/"]', function(e){
        e.preventDefault();
        router.navigate($(this).attr('href'),{trigger: true});
    });
});

当您加载页面并单击“#project”部分中的某个链接时,一切都表现正常。但是如果您刷新该页面,则会出现破坏页面的错误。
从控制台中可以看到:
Uncaught SyntaxError: Unexpected token < js/jquery.js:1
Uncaught SyntaxError: Unexpected token < js/underscore-min.js:1
Uncaught SyntaxError: Unexpected token < js/backbone.js:1
Uncaught SyntaxError: Unexpected token < erin.js:1

它还列出了以下内容:

...

Resource interpreted as Script but transferred with MIME type text/html: "http://localhost:8888/project/js/backbone.js". 

针对文档头部的所有链接和脚本。这些似乎都指向index.html文件的第一行。所以,如果我点击一个链接,它会从我的数据中输出我正在查找的img id,但如果我刷新页面或输入该链接,则会出现上面的错误。我是否正确地认为当有人访问该页面时,我应该能够保存链接domain.com/project/coolthing并使其正常工作?我错过了什么吗?是否实现了一些奇怪的东西?非常感谢给出正确方向的提示。

谢谢。


你能添加GalleryView的代码吗?至少包括加载模板的部分? - providencemac
@providencemac,我已经在顶部添加了那个。希望这有所帮助。 - Rchristiani
我完全不知道在哪里添加那个路由器解析的东西! - Nobody
3个回答

8
您在服务器端遇到了问题。您可能已经找到了解决方案的一半。
看起来您已经正确配置了服务器,使其在任何情况下都能发送您的应用程序HTML,除了具有优先权的资源(js,css)之外。
问题出现在您的主HTML中,其中引用了相对路径的JS文件。当您在pushState更新URL为/project/1后重新加载时,基本URL变为/project/
即。您拥有
<script src="js/backbone.js"></script>

当你应该拥有时
<script src="/js/backbone.js"></script>

因此,当浏览器尝试加载backbone.js时,它找不到它(/project/js/backbone.js不存在),并且命中服务器的catchall,传递应用程序HTML(因此解析错误会导致无法处理<)。
我的解释可能不是非常清晰,现在已经很晚了,但我相信您会理解!

非常简单,但就是这样。非常感谢。我会在能够的时候给你悬赏。 - Rchristiani
不客气。最简单的错误往往是最难追踪的! - thibauts

1
问题在于您在模板中使用的 href。Backbone 路由器正在监视站点 URL 的 # 符号后面的内容,即 hash 部分。
因此,您的 href 应该是: <a href="/#project/<%= id %>"> (注意 "project" 前面的 # 符号)
这样做的好处是,您甚至不需要单击处理程序,路由器将自动捕获哈希更改事件并相应地进行路由。

抱歉回复晚了,但这仍然不能解决我遇到的错误问题。如果我没记错的话,启用pushstate应该使我不必使用哈希符号。这样某人只需转到 ..../projects/someid 就能获取正确的信息。 - Rchristiani

1

两位评估者thibauts'providencemac's都是正确的。要么不使用pushState并使用哈希链接,要么在服务器上放置重写规则以发送静态内容。

最初加载此URL时 -

http://localhost:8888

同样,您的静态资源的URL也是这样的。
http://localhost:8888/js/backbone.js

实际问题是当您使用pushState并访问链接时,浏览器的URL会变成类似于这样的内容 -

http://localhost:8888/project/some_img_id

现在当您尝试重新加载页面时,索引文件将从此URL获取 -
http://localhost:8888/project/your_default.file   [index.html]

这意味着您的服务器找不到指定的文件,会自动返回默认的索引文件。

http://localhost:8888/your_default.file

当浏览器尝试访问静态文件时,它会再次默认使用索引文件。
http://localhost:8888/project/js/backbone.js

这就是错误的原因。因为它在JavaScript中找到了“<”字符,该字符无效。
Uncaught SyntaxError: Unexpected token < js/jquery.js:1

这个错误的原因是它试图解析的文件是JavaScript文件backbone.js,但它获取了你的index.html文件。
Resource interpreted as Script but transferred with MIME type text/html: "http://localhost:8888/project/js/backbone.js".

谢谢您的解释,非常有帮助!如果我能分赏金的话,我会这么做的。 - Rchristiani
不需要了,接受Thibauts的发现问题(为什么出错)你错过了。Providencemac的答案提到了另一个问题(出了什么问题)。我只是把这两个问题结合起来,说明了整个问题出在哪里。 - Mohit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接