vue.js系列二:组件化编码

1. 使用 vue-cli 创建模板项目

1.1 说明

  1. vue-cli 是 vue 官方提供的脚手架工具
  2. github: https://github.com/vuejs/vue-cli
  3. 作用: 从 https://github.com/vuejs-templates 下载模板项目

1.2创建 vue 项目
可先下载安装node.js

npm install -g vue-cli
vue init webpack vue_demo
cd vue_demo
npm install
npm run dev #需要到vue_demo目录下执行

图片.png

图片.png

访问: http://localhost:8080/
图片.png

1.3模板项目的结构

|-- build : webpack 相关的配置文件夹(基本不需要修改)
|-- dev-server.js : 通过 express 启动后台服务器
|-- config: webpack 相关的配置文件夹(基本不需要修改)
|-- index.js: 指定的后台服务的端口号和静态资源文件夹
|-- node_modules
|-- src : 源码文件夹
|-- components: vue 组件及其相关资源文件夹
|-- App.vue: 应用根主组件
|-- main.js: 应用入口 js
|-- static: 静态资源文件夹
|-- .babelrc: babel 的配置文件
|-- .eslintignore: eslint 检查忽略的配置
|-- .eslintrc.js: eslint 检查的配置
|-- .gitignore: git 版本管制忽略的配置
|-- index.html: 主页面文件
|-- package.json: 应用包配置文件
|-- README.md: 应用描述说明的 readme 文件
图片.png

1.3.1main.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'

Vue.config.productionTip = false

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

1.3.2App.vue

<!--
 定义组件标签的结构:
 1.内容:
 由<template></template>标签包裹
 2.行为:
 由<script></script>标签包裹
 3.样式
 由<style></style>标签包裹
 -->
<!--
引入其他组件的步骤
1.在<script></script>中引入組件并映射組件标签
import HelloWorld from './components/HelloWorld'
2.在<template></template>中使用组件标签
-->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 3.使用组件标签 -->
    <HelloWorld/>
  </div>
</template>

<script>
// 1.引入組件
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  // 2.映射組件标签
  components: {
    HelloWorld
  }
}
</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>

1.3.3components包下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>

2.项目的打包与发布

2.1项目打包

npm run build

会生成一个dist文件夹


图片.png

2.2发布
方法一: 使用静态服务器工具包

npm install -g serve
serve dist
访问: http://localhost:5000
   ┌───────────────────────────────────────────────────┐
   │                                                   │
   │   Serving!                                        │
   │                                                   │
   │   - Local:            http://localhost:5000       │
   │   - On Your Network:  http://192.168.177.1:5000   │
   │                                                   │
   │   Copied local address to clipboard!              │
   │                                                   │
   └───────────────────────────────────────────────────┘

方法二:使用动态 web 服务器(tomcat)

修改配置: webpack.prod.conf.js(在该处增加)
output: {
    publicPath: '/vue_demo/' //打包文件夹的名称
}
图片.png
重新打包:
npm run build
修改 打包后的dist 文件夹为项目名称: vue_demo
将 vue_demo文件夹拷贝到运行的 tomcat 的 webapps 目录下
访问: http://localhost:8080/vue_demo
图片.png

3.写一个demo-评论功能

3.1项目结构


图片.png

3.2index.html中引入bootstrap.css

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="stylesheet" href="./static/css/bootstrap.css">
    <title>vue_demo</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

3.3main.js

import Vue from 'vue'
import App from './App'

new Vue({
  el: '#app',
  components: {App},
  template: '<App/>'
});

3.4App.vue组件

<template>
  <div>
    <header class="site-header jumbotron">
      <div class="container">
        <div class="row">
          <div class="col-xs-12">
            <h1>请评论</h1>
          </div>
        </div>
      </div>
    </header>
    <div class="container">
      <Add :addComment="addComment"/>
      <List1 :comments="comments" :deleteComment="deleteComment"/>
    </div>
  </div>
</template>

<script>
  import Add from './components/Add.vue'
  import List1 from './components/List.vue'
  export default {
    data() { // 数据在哪里,操作数据的行为或方法就在哪里
      return {
        comments: [
          {
            name: 'tom',
            content: 'hello tom'
          },
          {
            name: 'jerry',
            content: 'hello, jerry'
          },
          {
            name: 'henry',
            content: 'hello, henry'
          }
        ]
      }
    },
    components: {
      Add,
      List1
    },
    methods: {
      // 添加Add.vue中的评论
      addComment(comment) {
        this.comments.unshift(comment);
      },
      // 删除List.vue中的评论
      deleteComment(index){
        this.comments.splice(index, 1);
      }
    }
  }
</script>

<style scoped>

</style>

3.5components包下的vue组件


图片.png

3.5.1List.vue组件-->展示评论功能

<template>
  <div class="col-md-8">
      <h3 class="reply">评论回复:</h3>
      <h2 v-show="comments.length===0" style='display: none'>暂无评论,点击左侧添加评论!!!</h2>
      <ul class="list-group">
        <Item v-for="(comment, index) in comments"
              :key="index"
              :comment="comment"
              :deleteComment="deleteComment"
              :index="index"/>
      </ul>
    </div>
</template>

<script>
  import Item from './Item.vue'
  export default {
    // 聲明接收屬性: 這個屬性就會成為組件對象的屬性
    props: ['comments', 'deleteComment'],
    components: {
        Item
    }
  }
</script>

<style scoped>
  .reply {
    margin-top: 0px;
  }

</style>

3.5.2Item.vue组件-->与List.vue组件一起展示评论

<template>
  <li class="list-group-item">
    <div class="handle">
      <a href="javascript:;" @click="deleteItem">删除</a>
    </div>
    <p class="user"><span >{{comment.name}}</span><span>:</span></p>
    <p class="centence">{{comment.content}}</p>
  </li>
</template>

<script>
    export default {
      props: {
        comment: Object,
        deleteComment: {
          type: Function,
          required: true
        },
        index: Number
      },
      methods: {
        deleteItem(){
          const {comment, index, deleteComment} = this;
          if(window.confirm(`确定删除${comment.name}的评论么`)){ // 这里是反引号,不是单引号
            deleteComment(index);
          }
        }
      }
    }
</script>

<style scoped>
  li {
    transition: .5s;
    overflow: hidden;
  }

  .handle {
    width: 40px;
    border: 1px solid #ccc;
    background: #fff;
    position: absolute;
    right: 10px;
    top: 1px;
    text-align: center;
  }

  .handle a {
    display: block;
    text-decoration: none;
  }

  .list-group-item .centence {
    padding: 0px 50px;
  }

  .user {
    font-size: 22px;
  }
</style>

3.5.3Add.vue组件--添加评论功能

<template>
  <div class="col-md-4">
      <form class="form-horizontal">
        <div class="form-group">
          <label>用户名</label>
          <input type="text" class="form-control" placeholder="用户名" v-model="name">
        </div>
        <div class="form-group">
          <label>评论内容</label>
          <textarea class="form-control" rows="6" placeholder="评论内容" v-model="content"></textarea>
        </div>
        <div class="form-group">
          <div class="col-sm-offset-2 col-sm-10">
            <button type="button" class="btn btn-default pull-right" @click="add">提交</button>
          </div>
        </div>
      </form>
    </div>
</template>

<script>
    export default {
      name: "Add",
      props: {
        addComment: { // 指定属性名,属性值的类型,必要性
          type: Function,
          required: true
        }
      },
      data() {
        return {
          name: '',
          content: ''
        }
      },
      methods: {
        add() {
          // 1.检查输入的合法性
          const name=this.name.trim();
          const content=this.content.trim();
          if(!name || !content){
            alert('输入不能为空');
            return;
          }
          // 2.根据输入的数据,封装成一个comment对象
          const comment = {
            name,
            content
          }
          // 3.添加到comments中
          // 数据在哪里,操作数据的行为或方法就在哪里:此处需要到App.vue里Add标签里添加方法
          this.addComment(comment);
          // 4.清除输入
          this.name='';
          this.content='';
        }
      }
    }
</script>

<style scoped>

</style>

3.6在当前路径下
启动项目

npm run dev

在浏览器中输入访问即可

http://localhost:8080

4.demo02-->计数器

图片.png

4.1index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="stylesheet" href="./static/css/bootstrap.css">
    <title>vue_demo</title>
    <style>
      .router-link-active {
        color: red !important;
      }
    </style>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

4.2main.js

import Vue from 'vue'
import App from './App'

let vm = new Vue({ // 配置對象的屬性名都是一些固定的屬性名,不能隨意修改
  el: '#app',
  components: {
    App // 映射组件标签
  },
  template: '<app/>' // 指定需要渲染到页面的模板
})

Vue.use({
  vm
})

4.3App.vue

<template>
  <div>
    <p>点击了{{count}}次,是{{oddOrEven}}</p>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementIfOdd">increment if odd</button>
    <button @click="incrementAsync">increment async</button>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        count: 0
      }
    },
    computed: {
      oddOrEven() {
        return this.count % 2 === 0 ? '偶数' : '奇数'
      }
    },
    methods: {
      increment () {
        const count = this.count
        this.count = count + 1
      },
      decrement () {
        const count = this.count
        this.count = count - 1
      },
      incrementIfOdd () {
        const count = this.count
        if (count % 2 === 1) {
          this.count = count + 1
        }
      },
      incrementAsync () { // 过1s才增加
        setTimeout(() => {
          const count = this.count
          this.count = count + 1
        }, 1000)
      }
    }
  }
</script>

<style scoped>

</style>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容