组件(Component)是自定义封装代码的功能。在前端开发过程当中,常常出现多个网页的功能是重复的,并且不少不一样的页面之间,也存在一样的功能。javascript
而在网页中实现一个功能,须要使用html定义功能的内容结构,使用css声明功能的外观样式,还要使用js来定义功能的特效,所以就产生了把一个功能相关的[HTML、css和javascript]代码封装在一块儿组成一个总体的代码块封装模式,咱们称之为“组件”。css
因此,组件就是一个html网页中的功能,通常就是一个标签,标签中有本身的html内容结构,css样式和js特效。html
这样,前端人员就能够在组件化开发时,只须要书写一次代码,随处引入便可使用。前端
vue的组件有两种:默认组件[全局组件] 和 单文件组件vue
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue.js"></script> <style> #nav input[type=text]{ width: 100px; } </style> </head> <body> <div id="app"> <!-- 2. 调用组件 --> <mynav></mynav> <mynav></mynav> <mynav></mynav> <mynav></mynav> </div> <script> // 1. 经过Vue类建立组件 // 组件与组件之间的数据,方法都是独立的,并且互相不会被影响。 Vue.component("mynav",{ template:`<div id="nav"> <button @click='sub()'>-</button> <input type='text' v-model='num'/> <button @click="add">+</button> </div>`, data(){ // 组件里面的变量数据 return { num: 0 } }, methods:{ // 组件里面的方法 sub(){ this.num--; }, add(){ this.num++; } }, watch:{ num(){ if(this.num<1){ this.num=0; } } } }); var vm = new Vue({ el:"#app", data:{ } }); </script> </body> </html>
前面学习了普通组件之后,接下来咱们继续学习单文件组件则须要提早先安装准备一些组件开发工具。不然没法使用和学习单文件组件。java
通常状况下,单文件组件,咱们运行在 自动化工具vue-CLI中,能够帮咱们把单文件组件编译成普通的js代码。因此咱们须要在电脑先安装搭建vue-CLI工具。node
官网:https://cli.vuejs.org/zh/python
Vue CLI 须要 Node.js 8.9 或更高版本 (推荐 8.11.0+)。你可使用 nvm 或 nvm-windows在同一台电脑中管理多个 Node 版本。webpack
nvm工具的下载和安装: https://www.jianshu.com/p/d0e0935b150aios
https://www.jianshu.com/p/622ad36ee020
curl -o- https://github.com/nvm-sh/nvm/v0.35.3/install.sh | bash
安装记录:
打开:https://github.com/coreybutler/nvm-windows/releases
安装完成之后,先查看环境变量是否设置好了.
经常使用的nvm命令
nvm list # 列出目前在nvm里面安装的全部node版本
nvm install node版本号 # 安装指定版本的node.js
nvm uninstall node版本号 # 卸载指定版本的node.js
nvm use node版本号 # 切换当前使用的node.js版本
若是使用nvm工具,则直接能够不用本身手动下载,若是使用nvm下载安装 node的npm比较慢的时候,能够修改nvm的配置文件(在安装根目录下)
# settings.txt
root: C:\tool\nvm [这里的目录地址是安装nvm时本身设置的地址,要根据实际修改]
path: C:\tool\nodejs
arch: 64
proxy: none
node_mirror: http://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/
Node.js是一个新的后端(后台)语言,它的语法和JavaScript相似,因此能够说它是属于前端的后端语言,后端语言和前端语言的区别:
运行环境:后端语言通常运行在服务器端,前端语言运行在客户端的浏览器上
功能:后端语言能够操做文件,能够读写数据库,前端语言不能操做文件,不能读写数据库。
咱们通常安装LTS(长线支持版本 Long-Time Support):
下载地址:https://nodejs.org/en/download/【上面已经安装了nvm,那么这里不用手动安装了】
node.js的版本有两大分支:
官方发布的node.js版本:0.xx.xx 这种版本号就是官方发布的版本
社区发布的node.js版本:xx.xx.x 就是社区开发的版本
Node.js若是安装成功,能够查看Node.js的版本,在终端输入以下命令:
node -v
在安装node.js完成后,在node.js中会同时帮咱们安装一个npm包管理器npm。咱们能够借助npm命令来安装node.js的包。这个工具至关于python的pip管理器。
npm install -g 包名 # 安装模块 -g表示全局安装,若是没有-g,则表示在当前项目安装
npm list # 查看当前目录下已安装的node包
npm view 包名 engines # 查看包所依赖的Node的版本
npm outdated # 检查包是否已通过时,命令会列出全部已过期的包
npm update 包名 # 更新node包
npm uninstall 包名 # 卸载node包
npm 命令 -h # 查看指定命令的帮助文档
npm install -g vue-cli
若是安装速度过慢,一直超时,能够考虑切换npm镜像源:http://npm.taobao.org/
使用vue-cli自动化工具能够快速搭建单页应用项目目录。
该工具为现代化的前端开发工做流提供了开箱即用的构建配置。只需几分钟便可建立并启动一个带热重载、保存时静态检查以及可用于生产环境的构建配置的项目:
// 生成一个基于 webpack 模板的新项目
vue init webpack 项目目录名
例如:
vue init webpack myproject
// 启动开发服务器 ctrl+c 中止服务
cd myproject
npm run dev # 运行这个命令就能够启动node提供的测试http服务器
运行了上面代码之后,终端下会出现如下效果提示:
src 主开发目录,要开发的单文件组件所有在这个目录下的components目录下
static 静态资源目录,全部的css,js,图片等资源文件放在这个文件夹
dist项目打包发布文件夹,最后要上线单文件项目文件都在这个文件夹中[后面打包项目,让项目中的vue组件通过编译变成js 代码之后,dist就出现了]
node_modules目录是node的依赖包目录
config是配置目录,
build是项目打包时依赖的目录
src/router 路由,后面须要咱们在使用Router路由的时候,本身声明.
整个项目是一个主文件index.html,index.html中会引入src文件夹中的main.js,main.js中会导入顶级单文件组件App.vue,App.vue中会经过组件嵌套或者路由来引用components文件夹中的其余单文件组件。
组件有两种:普通组件、单文件组件
普通组件的缺点:
html代码是做为js的字符串进行编写,因此组装和开发的时候不易理解,并且没有高亮效果。
普通组件用在小项目中很是合适,可是复杂的大项目中,若是把更多的组件放在html文件中,那么维护成本就会变得很是昂贵。
普通组件只是整合了js和html,可是css代码被剥离出去了。使用的时候的时候很差处理。
将一个组件相关的html结构,css样式,以及交互的JavaScript代码从html文件中剥离出来,合成一个文件,这种文件就是单文件组件,至关于一个组件具备告终构、表现和行为的完整功能,方便组件之间随意组合以及组件的重用,这种文件的扩展名为“.vue”,好比:"Home.vue"。
在组件中编辑三个标签,编写视图、vm对象和css样式代码。
template内部有且只能有一个子标签,组件全部的html代码必须被包含在这个子标签中。
<template> <div id="Home"> <span @click="num--" class="sub">-</span> <input type="text" size="1" v-model="num"> <span @click="num++" class="add">+</span> </div> </template>
<script> export default { name:"Home", data: function(){ return { num:0, } } } </script>
<style scoped> .sub,.add{ border: 1px solid red; padding: 4px 7px; } </style>
建立Homes.vue
<template> <div class="add_num"> <span @click="num++">+</span> <input type="text" size="2" v-model="num"> <span @click="num--">-</span> </div> </template> <script> export default{ name:"AddNum", data: function(){ return { num: 0, } } } </script> <style scoped> .add_num{ font-size: 32px; } </style>
在App.vue组件中调用上面的组件
<template> <div id="Home"> <span @click="num--" class="sub">-</span> <input type="text" size="1" v-model="num"> <span @click="num++" class="add">+</span> </div> </template> <script> export default { name:"Home", data: function(){ return { num:0, } } } </script> <style scoped> .sub,.add{ border: 1px solid red; padding: 4px 7px; } </style>
在开发vue项目以前,须要手动把 App.vue的HelloWorld组件代码以及默认的css样式,清楚。
上面的代码效果:
有时候开发vue项目时,页面也能够算是一个大组件,同时页面也能够分红多个子组件.
由于,产生了父组件调用子组件的状况.
例如,咱们能够声明一个组件,做为父组件
在components/建立一个保存子组件的目录HomeSon
在HomeSon目录下,能够建立当前页面的子组件,例如,是Menu.vue
// 组件中代码必须写在同一个标签中 <template> <div id="menu"> <span>{{msg}}</span> <div>hello</div> </div> </template> <script> export default { name:"Menu", data: function(){ return { msg:"这是Menu组件里面的菜单", } } } </script>
而后,在父组件中调用上面声明的子组件。
最后,父组件被App.vue调用.就能够看到页面效果.
效果:
例如,咱们但愿把父组件的数据传递给子组件.
能够经过props属性来进行数据传递.
传递数据三个步骤:
一、在父组件中,调用子组件的组名处,使用属性值的方式往下传递数据
<Menu :mynum="num" title="home里面写的数据"/> # 上面表示在父组件调用Menu子组件的时候传递了2个数据: 若是要传递变量[变量能够各类类型的数据],属性名左边必须加上冒号:,同时,属性名是自定义的,会在子组件中使用。 若是要传递普通字符串数据,则不须要加上冒号:
二、在子组件中接受上面父组件传递的数据,须要在vm组件对象中,使用props属性类接受。
<script> export default { name:"Menu", props:["mynum","title"], data: function(){ return { msg:"这是Menu组件里面的菜单", } } } </script> // 上面 props属性中表示接受了两个数据。
三、在子组件中的template中使用父组件传递过来的数据.
<template> <div id="menu"> <span>{{msg}},{{title}}</span> <div>hello,{{mynum}}</div> </div> </template>
效果:
步骤流程:
使用父组件传递数据给子组件时, 注意一下几点:
传递数据是变量,则须要在属性左边添加冒号.
传递数据是变量,这种数据称之为"动态数据传递"
传递数据不是变量,这种数据称之为"静态数据传递"
父组件中修改了数据,在子组件中会被同步修改,可是,子组件中的数据修改了,是否是影响到父组件中的数据.
这种状况,在开发时,也被称为"单向数据流"
<template> <div> <p>Post的子组件</p> <h2>{{fnum}}</h2> <p>data={{data}}</p> <p>fnum={{fnum}}</p> <div><input type="text" v-model="fnum"></div> </div> </template> <script> export default { name: "PostSon", // 父组件传递数据给子组件: 1. 在父组件中调用子组件的组件名称标签上面声明属性和传递值,2. 在子组件中经过props进行接收 props:["data","fnum"], // 接受父组件中传递过来的数据 // 子组件传递数据给父组件[事件的方式进行传递]: watch:{ fnum(){ console.log(this.fnum); // this.$emit("父元素的自定义事件","要传递的数据"); // 经过this.$emit()方法,子组件能够把数据传递给父组件 this.$emit("postparentdata",this.fnum); } } } </script> <style scoped> </style>
<template> <div> <h1>num={{num}}</h1> <Son data="我是付组件里面的内容" :fnum="num" @postparentdata="getsondata"></Son> </div> </template>
三、父组件中,声明一个自定义方法,在事件被调用时,执行的。
<script> import Son from "./PostSon" export default { name: "Post", data(){ return { num: 100, } }, components:{ Son:Son, }, methods:{ getsondata(message){ console.log("父组件"+message); this.num = message; } } } </script>
练习:
1. 在父组件中的data中声明一个num1的变量,值为10,传递到子组件中显示出来。
2. 在子组件中的data中声明一个num2的变量,值为50,传递到父组件中显示出来。
练习答案
<template> <div> <h1>我是Nav,{{parentnum}}</h1><button @click="num2++">点我</button> </div> </template> <script> export default { name: "Nav", props: ['parentnum'], data() { return { num2: 50 } }, mounted: { num2() { this.$emit('navfunc', 50) } }, // watch: { // num2(){ // this.$emit('navfunc', this.num2) // } // } } </script> <style scoped> </style>
<template> <div id="app"> <Home></Home> <input type="text" v-model="city"> <button @click="get_weather">获取天气</button> </div> </template> <script> import Home from './components/Home' export default { name: 'App', data() { return { city: '上海' } }, components: { Home, }, methods: { get_weather() { this.$axios.get('http://wthrcdn.etouch.cn/weather_mini?', { params: {city: this.city}, headers: {}, }).then(response => { console.log(response.data) }).catch(error => { console.log('请求失败') }) } } } </script> <style> </style>
1. 把课堂案例选项卡封装成组件,组件名:Card.vue
2. 把课堂案例获取天气封装成组件,组件名:Weather.vue
3. 使用组件化开发,完成以前的选项卡练习功能
4. 使用组件化开发,完成以前的todolist功能
5. 使用组件化开发,完成table表格的增删查改做业,数据使用本地存储进行保存