实现 vue-router 后 Vue.js 不工作

Posted

技术标签:

【中文标题】实现 vue-router 后 Vue.js 不工作【英文标题】:Vue.js not working after vue-router is implemented 【发布时间】:2020-07-24 11:41:03 【问题描述】:

这是我用来尝试创建单页应用程序的代码。我正在阅读有关 vue 路由器的信息,并尝试将其应用到我的项目中。我不确定代码有什么问题,但我看不到应用程序运行的页面。我在 chrom 控制台上遇到了一些错误,但这是在我将 vue 路由器添加到我的项目之后发生的。有什么解决办法吗?

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
    <link href="https://fonts.googleapis.com/css2?family=Courgette&display=swap" rel="stylesheet">


    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>

    <title>C safe!</title>
  </head>
  <body>

    <style>
    h1
      font-family: 'Courgette', cursive;
    
    .list-group 
      max-height: 300px;
      margin-bottom: 10px;
      overflow:scroll;
      -webkit-overflow-scrolling: touch;
    
    #map 
      height: 400px;
    
    </style>
    <div class="container-fluid bg-light p-0" id="app">

      <div class="row">
        <div class="col-sm-12 col-md-12 col-lg-12 p-5">
        <ul class="nav">
          <router-link to="/">
            <li class="nav-item">
              <a class="nav-link" href="#">Home</a>
            </li>
          </router-link>
        </ul>
        </div>
      </div>

    <script type="text/x-template" id="search-bar">
      <div class="row justify-content-center m-0" style="height:100vh;">
        <div class="col-sm-12 col-md-8 col-lg-8 p-5 mx-auto">
          <h1 class="mt-5 mb-3 text-center">C</h1>
          <div class="input-group">
              <input type="email" class="form-control rounded-0" v-on:change="instantSearch()" v-model="q" placeholder="Cerca nelle vicinanze es: Pizzeria">
            <div class="input-group-append">
              <button class="btn btn-outline-success rounded-0" v-on:click="instantSearch()">Cerca</button>
            </div>
          </div>
          <ul v-if="resultSet" class="list-group rounded-0">
            <small v-if="q" class="list-group-item rounded-0"><a class="text-muted" href="#" v-on:click="resetSearch()">Annulla</a></small>
            <router-link to="/results">
              <a v-for="result in resultSet" :key="result.id" v-on:click="expandMap(result.lat, result.lon)" href="#" class="list-group-item rounded-0" :place="result.display_name"> result.display_name </a>
            </router-link>
          </ul>
          <ul class="nav">
            <li class="nav-item">
              <a class="nav-link" href="#">FAQ</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">Aggiungi la tua attività</a>
            </li>
          </ul>
        </div>
      </div>
    </script>

    <script type="text/x-template" id="result-detail">
      <div class="collapse" id="map-collapsable">
        <div class="row m-0 results-map">
          <div class="col-sm-12 col-md-8 col-lg-8 p-0" id="map"></div>
          <div v-for="place in placeData" class="col-sm-12 col-md-4 col-lg-4">
           place.lat   place.lng 
          </div>
        </div>
      </div>
    </script>

    <router-view></router-view>
    </div>
<!-- TODO: Vue components -->

    <script src="app.js"></script>
  </body>
</html>

这是 JS vue 代码

window.onload = function()
  Vue.component('search-bar',
    template: '#search-bar',
    data()
      return 
    
  );

  Vue.component('view-result',
    template: '#result-detail',
    data()
      return 
    
  );

  const searchbar = template: 'search-bar'
  const result = template: 'view-result'

  const routes = [
    path: '/', component: searchbar,
    path: '/results', component: result
  ];

  const router = new VueRouter(
    routes // short for `routes: routes`
  );

  const web = new Vue(
    router,
    el: '#app',
    data: 
      pageData: [],
      resultSet: [],
      placeData: [],
      q: '',
      name: '',
    ,
    mounted: function()
      //this.initPage();
    ,
    ready: function()

    ,
    computed: 

    ,
    watch: 
      q: function(val, oldVal)
        this.instantSearch();
      
    ,
    methods: 
      instantSearch: function()
        axios.get('https://nominatim.openstreetmap.org/search?q='+this.q+'&format=json').then( (places) => 
          console.log(places);
          this.resultSet = [];
          places.data.forEach( (item, i) => 
            this.resultSet.push(item);
          );
        );
      ,
      resetSearch: function()
        this.resultSet = [];
        this.q = '';
      ,
      expandMap: function(lat, lng)
        let collapsable = document.getElementById('map-collapsable');
        console.log(lat, lng);
        //$(collapsable).collapse();
        this.placeData.push(lat: lat, lng: lng);
      ,
      initMap: function(data)

      
    
  ).$mount('#app');


我得到的错误如下:

vue.js:634 [Vue warn]: Property or method "result" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

(found in <Root>)
warn @ vue.js:634
warnNonPresent @ vue.js:2047
has @ vue.js:2092
eval @ VM258:3
Vue._render @ vue.js:3551
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
Vue._init @ vue.js:5012
Vue @ vue.js:5078
window.onload @ app.js:28
load (async)
(anonymous) @ app.js:1
vue.js:634 [Vue warn]: Error in render: "TypeError: Cannot read property 'display_name' of undefined"

(found in <Root>)
warn @ vue.js:634
logError @ vue.js:1893
globalHandleError @ vue.js:1888
handleError @ vue.js:1848
Vue._render @ vue.js:3553
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
Vue._init @ vue.js:5012
Vue @ vue.js:5078
window.onload @ app.js:28
load (async)
(anonymous) @ app.js:1
vue.js:1897 TypeError: Cannot read property 'display_name' of undefined
    at Proxy.eval (eval at createFunction (vue.js:11649), <anonymous>:3:1557)
    at Vue._render (vue.js:3551)
    at Vue.updateComponent (vue.js:4067)
    at Watcher.get (vue.js:4478)
    at new Watcher (vue.js:4467)
    at mountComponent (vue.js:4074)
    at Vue.$mount (vue.js:9044)
    at Vue.$mount (vue.js:11944)
    at Vue._init (vue.js:5012)
    at new Vue (vue.js:5078)
logError @ vue.js:1897
globalHandleError @ vue.js:1888
handleError @ vue.js:1848
Vue._render @ vue.js:3553
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
Vue._init @ vue.js:5012
Vue @ vue.js:5078
window.onload @ app.js:28
load (async)
(anonymous) @ app.js:1
vue.js:634 [Vue warn]: Cannot find element: #app
warn @ vue.js:634
query @ vue.js:5666
Vue.$mount @ vue.js:11882
window.onload @ app.js:83
load (async)
(anonymous) @ app.js:1
vue.js:634 [Vue warn]: Property or method "result" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

(found in <Root>)
warn @ vue.js:634
warnNonPresent @ vue.js:2047
has @ vue.js:2092
eval @ VM258:3
Vue._render @ vue.js:3551
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
window.onload @ app.js:83
load (async)
(anonymous) @ app.js:1
vue.js:634 [Vue warn]: Error in render: "TypeError: Cannot read property 'display_name' of undefined"

(found in <Root>)
warn @ vue.js:634
logError @ vue.js:1893
globalHandleError @ vue.js:1888
handleError @ vue.js:1848
Vue._render @ vue.js:3553
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
window.onload @ app.js:83
load (async)
(anonymous) @ app.js:1
vue.js:1897 TypeError: Cannot read property 'display_name' of undefined
    at Proxy.eval (eval at createFunction (vue.js:11649), <anonymous>:3:1557)
    at Vue._render (vue.js:3551)
    at Vue.updateComponent (vue.js:4067)
    at Watcher.get (vue.js:4478)
    at new Watcher (vue.js:4467)
    at mountComponent (vue.js:4074)
    at Vue.$mount (vue.js:9044)
    at Vue.$mount (vue.js:11944)
    at window.onload (app.js:83)
logError @ vue.js:1897
globalHandleError @ vue.js:1888
handleError @ vue.js:1848
Vue._render @ vue.js:3553
updateComponent @ vue.js:4067
get @ vue.js:4478
Watcher @ vue.js:4467
mountComponent @ vue.js:4074
Vue.$mount @ vue.js:9044
Vue.$mount @ vue.js:11944
window.onload @ app.js:83
load (async)
(anonymous) @ app.js:1

我不知道为什么,但在我创建组件并尝试使用 vue-router 之前,一切正常。

【问题讨论】:

【参考方案1】:

有几个问题:

    script type=text/x-templates 需要移出app div。否则,模板将作为app 模板的一部分进行处理,从而导致您在控制台中观察到undefined 错误。

    由于你的 Vue 声明已经指定了el: #app,你需要删除.$mount('#app')

    路由路径在 template: 'search-bar' template: 'result-detail' 中错误地指定了文字字符串模板。那应该分别是 template: '&lt;search-bar /&gt;' template: '&lt;result-detail /&gt;'

    qresultSet 数据属性应该移动到 search-bar 组件中。同样,placeData 数据属性应该移动到result-detail 组件中。

演示:

window.onload = function()
  Vue.component('search-bar',
    template: '#search-bar',
    data()
      return 
        resultSet: [],
        q: '',
      
    
  );

  Vue.component('view-result',
    template: '#result-detail',
    data()
      return 
        placeData: [],
      
    
  );

  const searchbar = template: '<search-bar />'
  const result = template: '<view-result />'

  const routes = [
    path: '/', component: searchbar,
    path: '/results', component: result
  ];

  const router = new VueRouter(
    routes // short for `routes: routes`
  );

  const web = new Vue(
    router,
    el: '#app',
    data: 
      pageData: [],
      name: '',
    ,
    mounted: function()
      //this.initPage();
    ,
    ready: function()

    ,
    computed: 

    ,
    watch: 
      q: function(val, oldVal)
        this.instantSearch();
      
    ,
    methods: 
      instantSearch: function()
        axios.get('https://nominatim.openstreetmap.org/search?q='+this.q+'&format=json').then( (places) => 
          console.log(places);
          this.resultSet = [];
          places.data.forEach( (item, i) => 
            this.resultSet.push(item);
          );
        );
      ,
      resetSearch: function()
        this.resultSet = [];
        this.q = '';
      ,
      expandMap: function(lat, lng)
        let collapsable = document.getElementById('map-collapsable');
        console.log(lat, lng);
        //$(collapsable).collapse();
        this.placeData.push(lat: lat, lng: lng);
      ,
      initMap: function(data)

      
    
  )

<script src="https://unpkg.com/vue@2.6.11/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-router@3.1.6/dist/vue-router.js"></script>

<style>
  h1
    font-family: 'Courgette', cursive;
  
  .list-group 
    max-height: 300px;
    margin-bottom: 10px;
    overflow:scroll;
    -webkit-overflow-scrolling: touch;
  
  #map 
    height: 400px;
  
</style>

<div class="container-fluid bg-light p-0" id="app">

  <div class="row">
    <div class="col-sm-12 col-md-12 col-lg-12 p-5">
      <ul class="nav">
        <router-link to="/">
          <li class="nav-item">
            <a class="nav-link" href="#">Home</a>
          </li>
        </router-link>
      </ul>
    </div>
  </div>

  <router-view></router-view>
</div>

<script type="text/x-template" id="search-bar">
  <div class="row justify-content-center m-0" style="height:100vh;">
    <div class="col-sm-12 col-md-8 col-lg-8 p-5 mx-auto">
      <h1 class="mt-5 mb-3 text-center">C</h1>
      <div class="input-group">
        <input type="email" class="form-control rounded-0" v-on:change="instantSearch()" v-model="q" placeholder="Cerca nelle vicinanze es: Pizzeria">
        <div class="input-group-append">
          <button class="btn btn-outline-success rounded-0" v-on:click="instantSearch()">Cerca</button>
        </div>
      </div>
      <ul v-if="resultSet" class="list-group rounded-0">
        <small v-if="q" class="list-group-item rounded-0"><a class="text-muted" href="#" v-on:click="resetSearch()">Annulla</a></small>
        <router-link to="/results">
          <a v-for="result in resultSet" :key="result.id" v-on:click="expandMap(result.lat, result.lon)" href="#" class="list-group-item rounded-0" :place="result.display_name"> result.display_name </a>
        </router-link>
      </ul>
      <ul class="nav">
        <li class="nav-item">
          <a class="nav-link" href="#">FAQ</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Aggiungi la tua attività</a>
        </li>
      </ul>
    </div>
  </div>
</script>

<script type="text/x-template" id="result-detail">
  <div class="collapse" id="map-collapsable">
    <div class="row m-0 results-map">
      <div class="col-sm-12 col-md-8 col-lg-8 p-0" id="map"></div>
      <div v-for="place in placeData" class="col-sm-12 col-md-4 col-lg-4">
         place.lat   place.lng 
      </div>
    </div>
  </div>
</script>

【讨论】:

感谢您的帮助。我是vue的新手,所以我现在犯了很多错误。从 vue 的主实例中,有什么我可以传递给组件的吗?我需要使用&lt;router-link&gt; 函数在点击即时搜索结果时更改视图 特别是搜索结果的详细信息需要传递给结果组件,不胜感激 @guggio 有几种方法可以处理这个问题。您可以在 search-bar 中实现 v-model,在 view-result 中实现公共属性。在app 中,使用本地数据道具将两者绑定在一起。我建议将其作为一个新问题提出,以获得更多有用的答案。

以上是关于实现 vue-router 后 Vue.js 不工作的主要内容,如果未能解决你的问题,请参考以下文章

vue-router源码实现

简单实现VUE-Router

一文搞定vue-router实现原理

Vue.js——vue-router 快速入门

Vue.js——vue-router 60分钟快速入门

Vue.js——vue-router 60分钟快速入门