天天看点

Vue项目 - 单文件组件和Vue中的路由

推荐:​​Vue汇总​​

Vue项目 - 单文件组件和Vue中的路由

什么是单文件组件

在之前的博客中,博主使用​

​Vue.component​

​​来定义全局组件,紧接着用​

​new Vue({ el: '#container '})​

​在每个页面内指定一个挂载点。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>组件</title>
  <script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
  <component v-bind:is="currentComponent">kaven</component>
  <button @click="click">切换</button>
</div>
</body>
</html>
<script>

  Vue.component("slot-welcome" , {
    template: `
           <div>
              <p>welcome </p>
              <slot></slot>
           </div>
        `
  });

  Vue.component("slot-hello" , {
    template: `
           <div>
              <p>hello </p>
              <slot></slot>
           </div>
        `
  });

  var vue = new Vue({
    el: '#div',
    data: {
      currentComponent: 'slot-hello'
    },
    methods: {
      click(){
        if(this.currentComponent === 'slot-hello'){
          this.currentComponent = 'slot-welcome'
        }
        else{
          this.currentComponent = 'slot-hello'
        }
      }
    }
  })
</script>      

这种方式在很多中小规模的项目中运作的很好,在这些项目里JavaScript只被用来加强特定的视图。但当在更复杂的项目中,或者你的前端完全由JavaScript驱动的时候,下面这些缺点将变得非常明显:

  1. 全局定义 ​

    ​(Global definitions)​

    ​​ :强制要求每个​

    ​component​

    ​中的命名不得重复。
  2. 字符串模板 ​

    ​(String templates)​

    ​​ :缺乏语法高亮,在HTML有多行的时候,需要用到丑陋的​

    ​\​

    ​。
  3. 不支持 CSS ​

    ​(No CSS support)​

    ​ :意味着当HTML和JavaScript组件化时,CSS明显被遗漏。
  4. 没有构建步骤 ​

    ​(No build step)​

    ​​ :限制只能使用HTML和ES5 JavaScript,而不能使用预处理器,如​

    ​Pug (formerly Jade)​

    ​​和​

    ​Babel​

    ​。

文件扩展名为 ​

​.vue​

​​的​

​single-file components​

​​ (单文件组件) 为以上所有问题提供了解决方法,并且还可以使用​

​webpack​

​​或​

​Browserify​

​等构建工具。

上一篇博客介绍了Vue项目的文件组成部分:​​Vue项目 - 项目文件介绍​​。

其中就有根组件​

​App.vue​

​:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>      

还有放置自定义组件的包​

​components​

​​中的​

​HelloWorld.vue​

​:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
    <ul>
      <li>
        <a
          href="https://vuejs.org"
          target="_blank"
        >
          Core Docs
        </a>
      </li>
      <li>
        <a
          href="https://forum.vuejs.org"
          target="_blank"
        >
          Forum
        </a>
      </li>
      <li>
        <a
          href="https://chat.vuejs.org"
          target="_blank"
        >
          Community Chat
        </a>
      </li>
      <li>
        <a
          href="https://twitter.com/vuejs"
          target="_blank"
        >
          Twitter
        </a>
      </li>
      <br>
      <li>
        <a
          href="http://vuejs-templates.github.io/webpack/"
          target="_blank"
        >
          Docs for This Template
        </a>
      </li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
      <li>
        <a
          href="http://router.vuejs.org/"
          target="_blank"
        >
          vue-router
        </a>
      </li>
      <li>
        <a
          href="http://vuex.vuejs.org/"
          target="_blank"
        >
          vuex
        </a>
      </li>
      <li>
        <a
          href="http://vue-loader.vuejs.org/"
          target="_blank"
        >
          vue-loader
        </a>
      </li>
      <li>
        <a
          href="https://github.com/vuejs/awesome-vue"
          target="_blank"
        >
          awesome-vue
        </a>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>      

这些都是单文件组件。

Vue项目 - 单文件组件和Vue中的路由

现在,大家应该都知道什么是单文件组件了,其实就是在单个文件中定义一个组件,这样对于组件的复用、修改都很方便;一个重要的事情值得注意,关注点分离不等于文件类型分离。在现代UI开发中,我们已经发现相比于把代码库分离成三个大的层次(HTML、CSS、Javascript)并将其相互交织起来,把它们划分为松散耦合的组件再将其组合起来更合理一些。在一个组件里,其模板、逻辑和样式是内部耦合的,并且把它们搭配在一起实际上使得组件更加内聚且更可维护。创建一个Vue项目后,当运行这个Vue项目时,基本上都会出现如下图所示页面。

Vue项目 - 单文件组件和Vue中的路由

那么为什么运行Vue项目,首页是上图所示页面呢?这就要涉及到Vue中的路由了。

首页​

​index.html​

​:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>project</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>      

很明显首页中​

​id="app"​

​​的​

​div​

​​标签被入口文件​

​main.js​

​中定义的组件挂载了。

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})      

而入口文件​

​main.js​

​​中定义的组件使用了根组件(App),并且定义模板​

​template​

​​为​

​<App/>​

​​,所以​

​<div id="app"></div>​

​​就相当于​

​<App/>​

​​;并且入口文件​

​main.js​

​​中还引入了​

​router​

​​,当引入​

​router​

​​后,Vue项目会自动加载文件夹​

​router​

​​下的文件​

​index.js​

​​,该文件定义了路由规则。ES6语法,当键和值相同时,如​

​router: router​

​​、​

​App: App​

​​就可以写成​

​router​

​​、​

​App​

​。

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})      

可以知道当路径为​

​'/'​

​​时,使用路由后,会被路由到​

​HelloWorld​

​组件。

而路由是在哪里触发的呢?其实是根组件中的​

​<router-view/>​

​​标签,因此这部分区域路由到了​

​HelloWorld​

​组件。

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>      

所以​

​<img src="./assets/logo.png">​

​对应于Vue的图片。

Vue项目 - 单文件组件和Vue中的路由

而​

​<router-view/>​

​​标签会路由到​

​HelloWorld​

​组件,对应于下面的文字和链接。

Vue项目 - 单文件组件和Vue中的路由

继续阅读