第一步:安装Node.js
第二步:全局安装vue-cli
npm install @vue/cli -g
第三步:创建一个基于 webpack 模板的新项目
(一)下载webpack离线模板
下载地址:
github.com/vuejs-templ…
下载好之后,将其解压到本地用户目录下的.vue-templates
目录下
(二) 创建项目
进入你的项目目录,创建一个基于 webpack 模板的新项目。比如说你想在E盘的Web文件夹下创建一个名为vue_demo的项目。则可以根据下面的流程来:
1.键盘 win+R
输入 cmd
回车
2.输入命令 e:
回车 进入到E盘
3.输入命令 CD web
回车 进入到web文件夹下
4.输入命令 vue init webpack vue_demo --offline
回车
按下回车后后进入一些项目的配置,刚开始使用Vue的话,大多数配置用默认的就行了,但是对新手来说Use ESLint to lint your code?
这个配置最好先选择No,因为如果选择Yes,它会用一种比较严格的模式来要求的你的代码编写的规范(即会有很多报错,比如某行代码前面只能有两个空格呀之类的都会报错)
创建好了之后,我们按照它的说明输入这两条命令
1.输入 cd vue_demo
回车 进入项目的目录
2.输入 npm run dev
回车 运行项目
项目开始编译,编译完了就会出现下面这个命令窗口
我们把它给我们的url复制到浏览器中
第四步:目录结构分析
到这里项目就创建好了,然后把项目文件夹拉进编译器里,VS或者WebStrom或者HbuildX都可以,我拉进HX里面,看个人喜好。
打开项目文件夹,看里面的文件目录结构如下
vue_demo : 项目文件夹,里面存放整个项目的代码
|-- build : webpack 相关的配置文件夹(基本不需要修改)
|-- dev-server.js : 通过 express 启动后台服务器
|-- config: webpack 相关的配置文件夹(基本不需要修改)
|-- index.js: 指定的后台服务的端口号和静态资源文件夹
|-- node_modules : 依赖文件夹
|-- src : 源码文件夹
|-- assets: 静态资源,如css,js,图片
|-- components: vue 组件及其相关资源文件夹
|-- router: 路由文件
|-- App.vue: 应用根主组件
|-- main.js: 应用入口 js
|-- static: 静态资源文件夹,一些公用的东西
|-- .babelrc: babel 的配置文件
|-- .eslintignore: eslint 检查忽略的配置
|-- .eslintrc.js: eslint 检查的配置
|-- .gitignore: git 版本管制忽略的配置
|-- index.html: 主页面文件
|-- package.json: 应用包配置文件
|-- README.md: 应用描述说明的 readme 文件
复制代码
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>vue_demo</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
复制代码
index.html一般只定义一个空的根节点,在main.js里面定义的实例将挂载在根节点下,内容都通过vue组件来填充。
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' //引入Vue,注意左边的Vue首字母大写,右边的vue全部小写,不能错
import App from './App' //引入组件App
import router from './router' //引入路由
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app', //挂载根节点,对应index.html中id="app"的div
router,
components: { App },//引入组件
template: '<App/>'//映射组件为标签
})
复制代码
main.js主要是引入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>
复制代码
一个vue页面通常由模板(template)、js(script)、样式(style)三部分组成。
- template
其中模板只能包含一个父节点,<router-view/>
为<router-view></router-view>
的简写,是子路由视图,后面的路由页面都显示在此处。
- script
vue通常用es6语法来写,用export default导出,其下面可以包含数据data,生命周期(mounted等),方法(methods)等。
- style
样式通过style标签包裹,默认是影响全局的,如需定义作用域只在该组件下起作用,需在标签上加scoped,<style scoped></style>
实例
按照下图的操作,先运行一次项目
此时有个问题就是,每次编译完后都要我们手动复制url去到浏览器,再打开,有点麻烦。我们可以通过修改config文件夹下的index.js文件中的autoOpenBrowser参数为true来使得每次编译完成后会自动打开浏览器。
需求分析
做一个留言板的功能,包括留言功能和显示留言功能
构建静态页面
使用BootStrap库构建静态页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>留言板</title>
<link rel="stylesheet" type="text/css" href="../../bootstrap-5.0.0-dist/css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="./Comment.css"/>
</head>
<body>
<div class="container-fluid">
<!-- 页面头部标题栏 -->
<div class="row clearfix comment-header">
<div class="col-md-12 column">
<div class="card text-center">
<div class="card-body">
<h1 class="card-title comment-title">Vue留言板</h1>
</div>
</div>
</div>
</div>
<!-- 页面内容,包括留言填写区域和留言查看区域 -->
<div class="row clearfix">
<!-- 留言填写区域 -->
<div class="col-md-4 column">
<div class="card">
<h5 class="card-header">请填写留言</h5>
<div class="card-body">
<div class="mb-3">
<textarea class="form-control" rows="3"></textarea>
</div>
<button type="button" class="btn btn-primary">提交留言</button>
</div>
</div>
</div>
<!-- 留言查看区域 -->
<div class="col-md-8 column">
<div class="card comment-card">
<h5 class="card-header">留言人1</h5>
<div class="card-body">
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="#" class="btn btn-primary">删除</a>
</div>
</div>
<div class="card comment-card">
<h5 class="card-header">留言人2</h5>
<div class="card-body">
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="#" class="btn btn-primary">删除</a>
</div>
</div>
<div class="card comment-card">
<h5 class="card-header">留言人3</h5>
<div class="card-body">
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="#" class="btn btn-primary">删除</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
复制代码
分析页面,抽取组件
分析上面的静态页面,可以发现,整个页面可以抽取出3个组件
在代码中抽取组件
所以,我们在src文件夹下的components文件夹下新建3个新的.vue文件,分别命名为Add,List,Item。
进行组件编写
要先在index.html中引入Bootstrap库。
App.vue
<template>
<div class="container-fluid">
<!-- 页面头部标题栏 -->
<div class="row clearfix comment-header">
<div class="col-md-12 column">
<div class="card text-center">
<div class="card-body">
<h1 class="card-title comment-title">Vue留言板</h1>
</div>
</div>
</div>
</div>
<!-- 页面内容,包括留言填写区域和留言查看区域 -->
<div class="row clearfix">
<!-- 留言填写区域 -->
<Add :addComment="addComment"/>
<!-- 留言查看区域 -->
<List :comments="Comments" :deleteComment="deleteComment"/>
</div>
</div>
</template>
<script>
import Add from './components/Add'
import List from './components/List'
export default {//数据在哪个组件,更新数据的方法就写在哪个组件
data(){
return {
// 通过组件间通信的方法将Comment数组传递到List组件
Comments:[
{
username:'AAA',
contents:'你好呀'
},
{
username:'BBB',
contents:'哈哈哈哈'
},
{
username:'CCC',
contents:'你真润'
},
]
}
},
methods:{
addComment(comment){
this.Comments.unshift(comment);
},
//删除指定下标的评论
deleteComment(index){
this.Comments.splice(index,1);
}
},
components: {
Add,
List
}
}
</script>
<style>
body {
margin: 10px;
}
.comment-header {
margin-bottom: 10px;
}
.comment-title {
font-size: 5rem;
}
.comment-card {
margin: 5px 0;
}
.card-body a,
button {
float: right;
}
</style>
复制代码
先不要看代码的其他的地方,只看标记的地方,这里是引入了两个组件Add和List组件。
然后Add组件有一个属性addComment,它的属性值addComment是定义在App.vue中的methods中的一个方法,其实就是把父组件的方法传递给子组件,让子组件可以调用。
List组件同理,父组件向List传递了一个Comment数组和一个deleteComment方法。
然后再看App.vue的script标签部分
import Add from './components/Add'
import List from './components/List'
复制代码
上面这两行的代码就是导入组件
export default {
components: {
Add,
List
}
}
复制代码
上面的代码则是将导入的组件映射为标签,所以我们才可以在<template></template>
中用<Add />
和<List />
这两个标签。
Add.vue
<template>
<div class="col-md-4 column">
<div class="card">
<h5 class="card-header">留言填写</h5>
<div class="card-body">
<div class="mb-3">
<label for="username" class="form-label">用户名</label>
<input type="email" class="form-control" id="username" placeholder="请输入用户名" v-model="username">
</div>
<div class="mb-3">
<label for="Contents" class="form-label">留言内容</label>
<textarea class="form-control" id="Contents" rows="3" placeholder="请输入留言内容" v-model="contents"></textarea>
</div>
<button type="button" class="btn btn-primary" @click="submitComment">提交留言</button>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
addComment: {
type:Function,
required:true
}
},
data() {
return {
username: '', //用户名
contents: '', //留言内容
}
},
methods: {
submitComment() {
// 1.判断数据是否合法
const username = this.username.trim(); //获取data中的username(利用trim去除两边的空格)
const contents = this.contents.trim();
if (!username || !contents) {
alert("输入的用户名或者留言内容不能为空");
return;
}
// 2.将数据封装成Comment对象
const Comment = {
username, //ES6的简洁语法
contents,
}
//添加到App.vue的comments数组中
this.addComment(Comment);
// 4.清除输入
this.username = "";
this.contents = "";
}
}
}
</script>
<style>
</style>
复制代码
Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在组件实例中访问这个值,就像访问 data 中的值一样。
props: {
addComment: {
type:Function,
required:true
}
},
复制代码
所以上面的代码的意思就是,给Add组件注册一个addComment自定义属性,然后这个属性接收的值的类型是个Function,且这个属性为必填的。
重新看一遍Add.vue的代码,可以知道这个组件的执行流程是,用户输入用户名和留言内容,v-model自动把数据收集到data中的username和contents中,然后点击提交留言按钮时,组件会执行methods中的事件submitComment,然后submitComment会先判断username和contents的值是否合法,合法则通过this.addComment调用父组件传进来的方法,这个方法则会将参数comment添加到父组件中的Comments数组中去。最后把username和contens的值置空。
List.vue
<template>
<div class="col-md-8 column">
<item v-for="(comment, index) in comments" :key="index" :comment="comment"
:deleteComment="deleteComment" :index="index"/>
</div>
</template>
<script>
import item from './Item.vue'
export default {
//声明接收属性:这个属性就会成为组件对象的属性
props:['comments','deleteComment'],//只指定了属性名称
components:{
item
}
}
</script>
<style>
</style>
复制代码
List组件比较简单,它里面包含着一个子组件Item,所以第一步是在List组件中引入Item组件,然后通过components参数把引入的Item组件映射为标签。
然后List组件的Props有两个,comments和deleteComment,其中comments是用来进行v-for循环的,里面存放的是要全部显示的留言的内容。deleteComment则是List作为中间组件传递给Item的方法,List自身用不到这个方法。由此可见,组件间的通信是要一层一层的传递的。
Item.vue
// 根组件
<template>
<div class="card comment-card">
<h5 class="card-header">{{comment.username}}</h5>
<div class="card-body">
<p class="card-text">{{comment.contents}}</p>
<a href="#" class="btn btn-primary" @click="deleteItem">删除</a>
</div>
</div>
</template>
<script>
export default {
props:{//指定了属性名和属性值的类型
comment:Object,
deleteComment:Function,
index:Number
},
methods:{
deleteItem(){
const {comment,index,deleteComment} = this;
if(window.confirm(`是否删除${comment.username}的留言?`)){
deleteComment(index);
}
}
}
}
</script>
<style>
</style>
复制代码
Item组件有3个Props,分别是comment、deleteComment、index。
comment和index是其父组件传给它的数据,comment是App组件data中的Comments数组中的一个元素,index则是这个元素在数组中的下标。
deleteComment则是App组件通过List组件传给Item组件的方法,用来从数组中删除元素的。
所以Item组件的执行方式是,点击删除按钮的时候,会执行组件的deleteItem方法,先通过ES6的对象解构复制获取到父组件传进来的deleteComment方法,然后再执行,就可以把App组件中的Comments数组中下标为index的元素删除了。