【Vue】基于脚手架创建Vue项目+Vue组件基本使用

第一步:安装Node.js

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)三部分组成。

  1. template

其中模板只能包含一个父节点,<router-view/><router-view></router-view>的简写,是子路由视图,后面的路由页面都显示在此处。

  1. script

vue通常用es6语法来写,用export default导出,其下面可以包含数据data,生命周期(mounted等),方法(methods)等。

  1. 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 defaultcomponents: {
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的元素删除了。

原创文章,作者:我心飞翔,如若转载,请注明出处:https://www.pipipi.net/14636.html

发表评论

登录后才能评论