【问题标题】:Vue.js not working after vue-router is implemented实现 vue-router 后 Vue.js 不工作
【发布时间】: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 之前,一切正常。

【问题讨论】:

    标签: vue.js vue-component


    【解决方案1】:

    有几个问题:

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

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

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

    4. 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 中,使用本地数据道具将两者绑定在一起。我建议将其作为一个新问题提出,以获得更多有用的答案。
    最近更新 更多