Vue学习(二)Vue组件化编程
文章目录
- 一、模块与组件相关概念说明
- 二、Vue 中使用组件的三大步骤
- 三、非单文件组件
- 四、单文件组件
- 4.1 Vue 单文件组件的组成
- 4.2 使用 vue-cli 创建模板项目
- 4.3 项目的打包与发布
- 五、组件化高级配置项
- 5.1 一个重要的内置属性
- 5.2 ref 属性
- 5.3 mixin
- 5.4 插件
- 5.5 scoped 样式
- 5.6 nextTick
- 六、组件间通讯
- 6.1 props 配置项
- 6.2 组件的自定义事件
- 6.3 全局事件总线(GlobalEventBus)
- 6.4 消息订阅与发布(pubsub)
- 七、Vue 过渡&动画
- 八、Vue 中的 Ajax
- 8.1 跨域问题
- 8.2 vue-resource
- 8.3 axios
- 九、组件化编程总结
一、模块与组件相关概念说明
① 模块
理解:向外提供特定功能的js
程序,一般就是一个js
文件
作用:通常js
文件很多很复杂,模块起到了复用js
,简化js
的编写,提高js
运行效率
② 组件
理解: 用来实现局部功能效果的代码集合(html
/css
/js
/image
……)
作用: 通常一个界面的功能很复杂,组件起到了复用编码,简化项目编码,提高运行效率
③ 模块化
当应用中的js
都以模块来编写的,那这个应用就是一个模块化的应用
④ 组件化
当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用。
二、Vue 中使用组件的三大步骤
① 定义组件
使用Vue.extend(options)
创建,其中options
和new Vue(options)
时传入的那个options
几乎一样,但也有点区别;
- 不要写
el
:最终所有的组件都要经过一个vm
的管理,由vm
中的el
决定服务哪个容器 data
必须写成函数:避免组件被复用时,数据存在引用关系
②注册组件
- 局部注册:靠
new Vue
的时候传入components
选项 - 全局注册:靠
Vue.component('组件名',组件)
③ 使用组件:使用组件标签<tag></tag>
三、非单文件组件
3.1 基本使用
非单文件组件说明:
- 模板编写没有提示
- 没有构建过程,无法将
ES6
转换成ES5
- 不支持组件的
CSS
真正开发中几乎不用
<!--使用组件标签-->
<school></school>
<student></student>
3.2 组件化命名规范
① 组件名
一个单词组成:
- 第一种写法(首字母小写):
school
- 第二种写法(首字母大写):
School
多个单词组成:
- 第一种写法(
kebab-case
命名):my-school
- 第二种写法(
CamelCase
命名):MySchool
(需要Vue
脚手架支持)
备注:
- 组件名尽可能回避
HTML
中已有的元素名称,例如:h2
、H2
都不行 - 可以使用
name
配置项指定组件在开发者工具中呈现的名字
② 组件标签
第一种写法:<school></school>
第二种写法:<school/>
备注:不用使用脚手架时,<school/>
会导致后续组件不能渲染。
③ 声明组件简写方式const school = Vue.extend(options)
可简写为const school = options
3.3 关于VueComponent
school
组件本质是一个名为VueComponent
的构造函数,是Vue.extend
生成的- 我们只需要写
<school/>
或<school></school>
,Vue
解析时会帮我们创建school
组件的实例对象即Vue
帮我们执行new VueComponent(options)
- 每次调用
Vue.extend
,返回的都是一个全新的VueComponent
VueComponent
的实例对象简称vc
- 关于
this
指向:组件配置中data
函数、methods
中的函数、watch
中的函数、computed
中的函数 它们的this
均是vc
四、单文件组件
4.1 Vue 单文件组件的组成
① 模板页面
<template>
页面模板
</template>
② JS 模块对象
<script>
//vue.extends({})的简写
exprot default{
data(){
return{ }
},
methods: { },
computed:{ },
components: { }
}
</script>
③ 样式
<style>
样式定义
<style/>
4.2 使用 vue-cli 创建模板项目
① 创建vue
项目
vue-cli是vue官方提供的脚手架工具
# 安装vue-cli
npm install -g vue-cli
# 构建vue项目
vue init webpack vue-demo
# 安装依赖
npm install
# 运行项目
npm run dev
访问localhost:8080
,效果如下:
② 模板项目结构
③ template属性的作用template
参数绑定的组件替换给绑定的el
标签值对应的index.html
中的元素app
。
④ render 函数
vue.js
与vue.runtime.xxx.js
的区别:
vue.js
是完整版的Vue
,包含核心功能+模板解析器vue.runtime.xxx.js
是运行版的Vue
,只包含核心功能;没有模板解析器
因为vue.runtime.xxx.js
没有模板解析器,所以不能使用template
配置项,需要使用。
render
函数接收到的createElement
函数去指定具体内容,实现了将App
组件放入容器中。
⑤ eslint:用于做项目编码规范检查的工具
基本原理:定义了很多规则,检查项目的代码一旦发现违背了某个规则就输出相应的提示信息有相应的配置,可定制检查。
webstorm
关闭编码时候的检查:setting
->搜索ESLint
->关闭Enable
。
⑥ vue.config.js配置文件
- 使用
vue inspect > output.js
可以查看到Vue
脚手架的默认配置 - 使用
vue.config.js
可以对脚手架进行个性化定制,详情见地址
4.3 项目的打包与发布
① 打包
# 使用该命令生成dist文件
npm run build
② 发布
方式一:使用静态服务器工具包
# 安装静态服务器
npm install -g serve
# 运行项目
serve dist
# 访问所给连接即可
方式二:使用动态web
服务器(tomcat
),将生成的dist
文件扔到tomcat
的webapp
下即可。
五、组件化高级配置项
5.1 一个重要的内置属性
一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
。
为什么要有这个关系:让组件实例对象(vc
)可以访问到Vue
原型上的属性、方法。
5.2 ref 属性
- 被用来给元素或子组件注册引用信息(
id
的替代者) - 应用在
html
标签上获取的是真实DOM
元素,应用在组件标签上是组件实例对象(vc
) 使用方式:
- 打标识:
<h1 ref="xxx">.....</h1>
或<School ref="xxx"></School>
- 获取:
this.$refs.xxx
- 打标识:
参考代码如下:
<template>
<div id="app">
<h1 ref="msg">{ { msg}}</h1>
<School ref="school"/>
<button @click="showDom">showDom</button>
</div>
</template>
<script>
import School from './components/School.vue'
export default {
name: 'App',
components: {
School
},
data(){
return{
msg:'----Vue学习----'
}
},
methods:{
showDom(){
console.log(this.$refs.school)
console.log(this.$refs.msg)
}
}
}
</script>
<style>
</style>
5.3 mixin
mixin
功能:可以把多个组件共用的配置提取成一个混入对象
使用方式:
- 定义混入
使用混入
- 全局混入:
Vue.mixin(xxx)
- 局部混入:
mixins:['xxx']
- 全局混入:
示例代码:
定义混入mixin.js
:
export const mixin1 = {
methods: {
showName() {
alert(this.name)
}
},
mounted() {
console.log('你好啊!')
}
}
局部混入:
<script>
import { mixin1} from '../mixin.js'
export default {
name: 'School',
data () {
return {
name:'Peking',
location: 'Beijing'
}
},
mixins:[mixin1]
}
</script>
全局混入main.js
import Vue from 'vue'
import App from './App'
import { mixin1} from './mixin.js'
Vue.config.productionTip = false
Vue.mixin(mixin1)
new Vue({
el: '#app',
render: h => h(App)
})
5.4 插件
插件功能:用于增强Vue
,插件的功能范围没有严格的限制,一般有下面几种:
- 添加全局方法或者属性,如:
vue-custom-element
- 添加全局资源(指令/过滤器/过渡等),如
vue-touch
- 通过全局混入来添加一些组件选项,如
vue-router
- 添加
Vue
实例方法,通过把它们添加到Vue.prototype
上实现。 - 一个库,提供自己的
API
,同时提供上面提到的一个或多个功能,如vue-router
本质:包含install
方法的一个对象,install
的第一个参数是Vue
,第二个以后的参数是插件使用者传递的数据。
自定义插件:
对象.install = function (Vue, options) {
// 1. 添加全局过滤器
Vue.filter(....)
// 2. 添加全局指令
Vue.directive(....)
// 3. 配置全局混入(合)
Vue.mixin(....)
// 4. 添加实例方法
Vue.prototype.$myMethod = function () { ...}
Vue.prototype.$myProperty = xxxx
}
使用插件:Vue.use()
示例代码:
定义插件方式一:
//插件定义方式一
// export default {
// install(Vue, x, y, z) {
// console.log(x, y, z)
// //定义混入
// Vue.mixin({
// methods: {
// showName() {
// alert(this.name)
// }
// }
// })
// }
// }
//插件定义方式二
const MyPlugin = { }
MyPlugin.install = function(Vue, a,b,c) {
console.log(a,b,c)
//定义混入
Vue.mixin({
methods: {
showName() {
alert(this.name)
}
}
})
}
export default MyPlugin
使用插件main.js
:
import Vue from 'vue'
import App from './App'
// import plugin from './plugin.js'
import MyPlugin from './plugin.js'
Vue.config.productionTip = false
Vue.use(MyPlugin, 1, 2, 3)
new Vue({
el: '#app',
render: h => h(App)
})
测试效果:使用插件后Vue
获得了混入属性
5.5 scoped 样式
作用:让样式在局部生效,防止冲突。
写法:<style scoped>
5.6 nextTick
语法:this.$nextTick(回调函数)
作用:在下一次DOM
更新结束后执行其指定的回调。
什么时候用:当改变数据后,要基于更新后的新DOM
进行某些操作时,要在nextTick
所指定的回调函数中执行。
六、组件间通讯
6.1 props 配置项
props
功能是让组件接收外部传过来的数据,传递数据的方式:<Demo name="xxx"/>
,当传递数据类型不为String
类型的时候,应使用<Demo :age="xxx"/>
,接收方式有如下3种方式:
- 第一种方式(只接收):
props:['name']
- 第二种方式(限制类型):
props:{name:String}
- 第三种方式(限制类型、限制必要性、指定默认值):
③ props 属性
- 父组件 ==> 子组件 通信
子组件 ==> 父组件 通信(要求父先给子一个函数)
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
因此在使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
组件Student
代码:
<template>
<div>
<h2>姓名:{ { name }}</h2>
<h2>年龄:{ { age+1 }}</h2>
<h2>家乡:{ { home }}</h2>
</div>
</template>
<script>
export default {
name: 'Student',
data() {
return {
name: 'Joker',
age: this.parent_age,
home: 'Beijing'
}
},
//1、简单的声明接收
// props:['name','age','home'],
//2、对数据类型进行限制
// props: {
// name: String,
// age: Number,
// home: String
// },
//3、接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
props: {
name: {
type: String, //name的类型是字符串
required: true, //name是必要的
},
parent_age: {
type: Number,
default: 99 //默认值
},
home: {
type: String,
required: true
}
}
}
</script>
<style>
</style>
App.vue
代码:
<template>
<div id="app">
<h1 ref="msg">{ { msg}}</h1>
<Student name="Frank" :parent_age="14" home="Shanghai"/>
</div>
</template>
<script>
import Student from './components/Student.vue'
export default {
name: 'App',
components: {
Student
},
data(){
return{
msg:'----Vue学习----'
}
}
}
</script>
<style>
</style>
6.2 组件的自定义事件
前面我们讲过子组件向父组件通信可以使用props
属性,但需要父组件传递给子组件回调函数。我们可以采用组件的自定义事件同样达到子组件传递父组件通信。
使用场景:A
是父组件,B
是子组件,B
想给A
传数据,那么就要在A
中给B
绑定自定义事件(事件的回调在A
中)
① 绑定自定义事件
- 在父组件中
<School @schoolEvent="getSchoolName"/>
或<School v-on:schoolEvent="getSchoolName"/>
第二种方式,在父组件中定义事件:
<Student ref="student"/>
//在mounted函数中绑定
mounted(){
this.$refs.student.$on('studentEvent', this.getStudentName)
}
- 若想让自定义事件只能触发一次,可以使用
once
修饰符,或$once
方法,例:this.$refs.student.$once('atguigu',this.getStudentName)
② 触发自定义事件
this.$emit('studentEvent', this.name, 3, 4, 5)
③ 解绑自定义事件
- 解绑具体事件:
this.$off('schoolEvent')
- 解绑多个事件:
this.$off(['schoolEvent', 'testEvent'])
- 解绑所有事件:
this.$off()
④ 组件上也可以绑定原生DOM
事件,需要使用native
修饰符
⑤ 注意事项
注意:通过this.$refs.xxx.$on('atguigu',回调)
绑定自定义事件时,回调要么配置在methods
中,要么用箭头函数,否则this
指向会出问题!
6.3 全局事件总线(GlobalEventBus)
一种组件间通信的方式,适用于任意组件间通信。
① 安装全局事件总线
new Vue({
......
beforeCreate() {
//安装全局事件总线,$bus就是当前应用的vm
Vue.prototype.$bus = this
},
......
})
② 使用事件总线
接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
methods(){
demo(data){ ......}
}
......
mounted() {
this.$bus.$on('xxxx',this.demo)
}
- 提供数据:
this.$bus.$emit('xxxx',数据)
- 解绑事件:最好在
beforeDestroy
钩子中,用$off
去解绑当前组件所用到的事件
6.4 消息订阅与发布(pubsub)
- 一种组件间通信的方式,适用于任意组件间通信。
使用步骤:
- 安装
pubsub
:npm i pubsub-js
- 引入:
import pubsub from 'pubsub-js'
接收数据:
A
组件想接收数据,则在A
组件中订阅消息,订阅的回调留在A
组件自身。methods(){
demo(data){ ......}
}
......
mounted() {
this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
}
- 提供数据:
pubsub.publish('xxx',数据)
- 最好在
beforeDestroy
钩子中,用PubSub.unsubscribe(pid)
去取消订阅。
- 安装
七、Vue 过渡&动画
vue
动画:操作css
的trasition
或animation
,vue
会给目标元素添加/移除特定的class
。
过渡的相关类名:
- xxx-enter-active
: 指定显示的transition
- xxx-leave-active
: 指定隐藏的transition
- xxx-enter
/xxx-leave-to
: 指定隐藏时的样式
基本过渡动画的编码:
1)准备好样式
- 元素进入的样式
-v-enter
:进入的起点
-v-enter-active
:进入过程中
-v-enter-to
:进入的终点 - 元素离开的样式
-v-leave
:离开的起点
-v-leave-active
:离开过程中
-v-leave-to
:离开的终点
2)使用<transition>
包裹要过度的元素,并配置name
属性
3)若有多个元素需要过度,则需要使用<transition-group>
,且每个元素都要指定key
值
<style type="text/css">
.fade-enter-active, .fade-leave-active {
transition: opacity 1s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>
<div id="app">
<button @click="show=!show">
过渡&动画
</button>
<transition name="fade">
<p v-if="show">Hello</p>
</transition>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
show: true
}
})
</script>
效果:
八、Vue 中的 Ajax
8.1 跨域问题
① 脚手架配置代理解决方法一
在vue.config.js
中添加如下配置:
devServer:{
proxy:"http://localhost:5000"
}
说明:
- 优点:配置简单,请求资源时直接发给前端(8080)即可。
- 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
- 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
② 脚手架配置代理方法二
编写vue.config.js
配置具体代理规则:
module.exports = {
devServer: {
proxy: {
'/api1': { // 匹配所有以 '/api1'开头的请求路径
target: 'http://localhost:5000',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: { '^/api1': ''}
},
'/api2': { // 匹配所有以 '/api2'开头的请求路径
target: 'http://localhost:5001',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: { '^/api2': ''}
}
}
}
}
/* changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000 changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080 changeOrigin默认值为true */
说明:
- 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
- 缺点:配置略微繁琐,请求资源时必须加前缀。
8.2 vue-resource
vue
插件,非官方库,vue1.x
使用广泛。
- 安装
vue-resource
:npm i vue-resource
main.js
中引入VueResource
模块import VueResource from 'vue-resource'
Vue.use(VueResource)
通过
vue
组件对象发送ajax
请求<script>
new Vue({
methods: {
testVueResource() {
this.$http.get('/someUrl').then((response) => {
console.log(response.data)
}, (error) => {
console.log(error.statusText)
})
}
}
})
</script>
8.3 axios
通用的ajax
请求库,官方推荐,vue2.x
使用广泛。实例参考axios 学习
。
九、组件化编程总结
① 组件的拆分
通常我们是对已有的传统前端项目进行改造成Vue
项目,比如下方这个静态页面:
拿到这个静态资源后我们需要对静态资源进行组件上的拆分,如下图,我们将静态资源分成了三大部分:UserHeader
、UserList
、UserFooter
,其中UserList
又是由多个UserItem
组成。
首先我们先创建各个组件,然后将静态资源html
和css
放入到App
,然后将对应的html
和css
样式移入到对应的组件中。
通过分析,我们Todos
数据在各个组件均会用到,那么我们边将数据定义在App
组件中,我们通过props
属性将父级数据传递给子级数据。
② 组件化编码流程
- 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突
实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用
- 一个组件在用:放在组件自身即可
- 一些组件在用:放在他们共同的父组件上(状态提升)
- 实现交互:从绑定事件开始
④ webStorage
- 存储内容大小一般支持5
MB
左右(不同浏览器可能还不一样) - 浏览器端通过
Window.sessionStorage
和Window.localStorage
属性来实现本地存储机制。 - 相关
API
:
1)xxxxxStorage.setItem(‘key’, ‘value’):该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
2)xxxxxStorage.getItem(‘person’):该方法接受一个键名作为参数,返回键名对应的值
3)xxxxxStorage.removeItem(‘key’):该方法接受一个键名作为参数,并把该键名从存储中删除
4)xxxxxStorage.clear():该方法会清空存储中的所有数据 备注:
1)
SessionStorage
存储的内容会随着浏览器窗口关闭而消失
2)LocalStorage
存储的内容,需要手动清除才会消失
3)xxxxxStorage.getItem(xxx)
如果xxx
对应的value
获取不到,那么getItem
的返回值是null
4)JSON.parse(null)
的结果依然是null
还没有评论,来说两句吧...