Vue2技术整理2 - 核心篇 - 更新完毕
2、组件化开发
前言
- 基础篇链接:https://www.cnblogs.com/xiegongzi/p/15782921.html
2.1、认识组件概念
- 对于学Java的人来说的话,这个词所要表达的意思再熟悉不过了,所谓组件就是:面向对象中的抽象、封装思想,而所谓的组件化就是:把功能用多组件的方式搭配起来编写( 有一个根组件,旗下有N多微型组件 ,粗暴理解就是:SpringCloud中的main()方法可以搭配很多不同功能的注解,main()方法就是根组件,不同功能的注解就是微型组件 ),而这些功能组成的应用程序就是一个组件化应用,因此:这样做之后,好处就是利于维护和提高代码的复用性了
- 但是对于前端的人来说,这个东西就需要特别解释一下:直接下定义就是 实现应用中局部功能代码和资源的集合
- 瞄一下官网,它里面有一个图
- 所以:现在就可以理解前面下的定义为什么是局部功能代码和资源的集合了,局部功能就是某一个模块,是针对这个模块内部的,而这个模块内部的编写不就是CSS、HTML片段、JS代码吗,同时png、mp3等等这些就是资源咯
- 瞄一下官网,它里面有一个图
- 至于为什么要学组件化开发?
- 一是因为做的应用页面都是很复杂的,如果使用传统的CSS+HTML+JS,那么就会出现很多的js文件,不利于维护和 编写很费力的
- 二是因为组件化开发可以极好的复用代码、简化项目代码、所以也就提高了运行效率
同时组件又有单文件组件( 真实开发玩的 ) 和 非单文件组件
- 单文件组件:就是指只有一个组件组成( 即:是一个.vue的文件 )
- 非单文件组件:就是有N多个组件组成
2.2、非单文件组件
2.2.1、使用组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>玩一下组件</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<!-- 被 vm 实例所控制的区域 -->
<div id="app">
<!-- 3、使用组件 -->
<person></person>
<hr/>
<hobbys></hobbys>
</div>
<script>
// 去除浏览器控制台中的警告提示信息
Vue.config.productionTip = false;
// 玩组件三板斧
// 1、创建组件
const person = Vue.extend({
// 这里在基础篇中怎么玩就怎么玩,相应的也有watch、computed.....
// 但是:切记:不可以用el和data必须是函数式
/*
不可以用el的原因是:el指向的是具体的容器,这是根组件做的事情,现在这是是小弟
不可以用data对象式,而必须用函数式:是因为对象是一个引用地址嘛( 玩java的人很熟悉这个对象的事情 )
如果用对象一是Vue直接不编译、报错,二是就算可以用对象式,那几个变量都可以
指向同一个对象了,因此就会产生:一个变量修改了对象中的东西,那么另一个变量指向
的是同一个对象,因此:这个变量指向的数据也会发生改变
而函数式则不会,因为:函数式就是哪个变量用的,里面的return返回值就属于哪个变量
*/
// 使用模板,这个就需要直接写在组件里面了( 让当前组件的内容显示出来嘛 ),如果:放到div容器的模板中,是会报错的
template: `
<div>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h2>{{sex}}</h2>
</div>
`,
// 切记:这里是使用data的另一种写法 —— 函数式,必须用
data(){
return {
name: \'紫邪情\',
age: 18,
sex: \'女\'
}
}
})
// 再创建一个组件
const hobbys = Vue.extend({
template: `
<div>
<h2>{{one}}</h2>
<h2>{{two}}</h2>
<h2>{{three}}</h2>
</div>
`,
data(){
return {
one: \'抠脚\',
two: \'玩\',
three: \'酒吧\'
}
}
})
// 创建 vm 实例对象
const vm = new Vue({
// 指定控制的区域
el:\'#app\',
// 这里面也可以使用这个编写data,当然也可以不写,里面要写哪些和以前一样
data:{},
// 2、注册组件
components: {
// 前为 正式在页面中用的组件名( div模板中用的名字 ) 后为组件所在位置
// person: person, // 这种同名的就可以简写
// 简写
person,
hobbys
}
});
</script>
</body>
</html>
组件小结
- Vue中使用组件的三板斧
- 1、创建组件
- 2、注册组件
- 3、使用组件( 写组件标签即可 )
- 如何定义一个组件?
- 使用Vue.extend( { options } )创建,其中options 和 new Vue( { options } )时传入的哪些option“几乎一样”,区别就是:
- 1、el不要写 ——— 因为最终所有的组件都要经过一个vm的管理( 根组件 ),由vm中的el决定服务哪个容器
- 2、data必须写成函数式 ———— 因为可以避免组件被复用时,数据存在引用关系
- 另外:template选项可以配置组件结构
- 使用Vue.extend( { options } )创建,其中options 和 new Vue( { options } )时传入的哪些option“几乎一样”,区别就是:
- 如何注册组件?
- 1、局部注册: 靠new Vue的时候传入components选项
- 2、全局注册:靠Vue。component( \'组件名\' , 组件 )
- 真实开发中一般都是玩的局部组件,局部变全局一般都是一样的套路,去掉s,然后使用Vue来调,最后加入相应的名字和配置即可
- 最后编写组件标签即可使用,如:
<person></person>
2.2.2、使用组件的注意点
1、创建组件时的简写问题
// 1、创建局部组件( 完整写法 )
const person = Vue.extend({
template: `
<div>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
</div>
`,
data(){
return {
name: \'紫邪情\',
age: \'女\'
}
}
})
// 简写形式
const person2 = {
template: `
<div>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
</div>
`,
data(){
return {
name: \'紫邪情\',
age: \'女\'
}
}
}
上面两种都可以
- 但是:简写形式在底层其实也调用了Vue.extend()
- 验证完了,记得把源码的断点去掉
2、组件名的问题
- (1)、组件名为一个单词时
- 使用全小写字母 / 首字母大写都没问题
- 使用全小写字母 / 首字母大写都没问题
- (2)、组件名为多个单词组成时
- 全部用小写 / 使用 - 进行分割都没问题( 此种分割需要注意在注册时的方式,加单引号 )
- 还有一种就是上图中的效果:大驼峰命名
- 但是:这种大驼峰命名需要注意,有些人就不可以( 因为:严格来说这种命名是后续的技术 —— 使用脚手架时的方式 ),但是:有些人又可以,而且不报错,比如我上图中的效果,因为这是Vue版本的问题【 最近才下的Vue的话,是新的,此种命名方式就是可以的,但是:在还没接触脚手架之前可以测试玩,先别正式用啊 】,要看源码的话,从下图这里往后看即可
- 但是:这种大驼峰命名需要注意,有些人就不可以( 因为:严格来说这种命名是后续的技术 —— 使用脚手架时的方式 ),但是:有些人又可以,而且不报错,比如我上图中的效果,因为这是Vue版本的问题【 最近才下的Vue的话,是新的,此种命名方式就是可以的,但是:在还没接触脚手架之前可以测试玩,先别正式用啊 】,要看源码的话,从下图这里往后看即可
- (3)、注意组件名别和HTML中的原生标签名一致,会冲突报错,HTML的限制就是上图中看源码中的哪些( 别想着它是小写,你搞大写,也是不行的^ _ ^ ),如果非要用HTML标签名,让人见名知意,那就在原生HTML标签名前加一些特定的词,如:user-input这种【 一般加的前缀都是功能点名称 】,记得千万别用:input、h2....此类名字来命名组件名
- 全部用小写 / 使用 - 进行分割都没问题( 此种分割需要注意在注册时的方式,加单引号 )
3、关于组件在使用时的注意项
- (1)、可以使用开放标签,如:
<my-info></my-info>
,这种肯定没任何问题 - (2)、也可以使用自闭合标签,如:
<my-info/>
,但是这种有坑,这种使用方式需要脚手架支持,否则渲染时会出问题
2.2.2.1、使用组件注意点总结
- 1、关于组件名
- 一个单词组成时
- (1)、全小写,如:person
- (2)、首字母大写,如:Person
- 多个单词组成时
- (1)、全小写,如:myinfo
- (2)、使用 - 分割,如:my-info
- (3)、驼峰命名,如:MyInfo,但注意:目前没用脚手架之前最好别用,是因为指不定一会好使,一会不好使
- 注意事项:
- (1)、组件名最好别和HTML的标签名一致,从而造成冲突( 非要用,可以采用加词 / 使用 - 分割 )
- (2)、可以在创建组件时,在里面配置name选项,从而指定组件在Vue开发者工具中呈现的名字
- 此种形式在第三方组件时会见到
- 一个单词组成时
- 2、关于组件标签( 使用组件 )
- (1)、使用开放标签也行,如:
<my-info></my-info>
- (2)、使用自闭合标签也行,如:
<my-info/>
- 但是:此种方式目前有坑,会出现后续组件不能渲染的问题,所以需要等到后续使用脚手架时才可以
- (1)、使用开放标签也行,如:
- 3、创建组件的简写形式
- const person = Vue.extend( { 配置选项 } ) 可以简写为 const person = { 配置选项 }
2.2.3、组件的嵌套 / 子父组件
- 很有用啊,真实开发玩的是单文件组件,逃不开这个点的,而且还会有子父组件通信和兄弟组件通信
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>组件嵌套</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<!-- 被 vm 实例所控制的区域 -->
<div id="app">
<!-- 3、使用组件 -->
<info></info>
</div>
<script>
// 去除浏览器控制台中的警告提示信息
Vue.config.productionTip = false;
// 1、定义组件
const person = {
template: `
<div>
<h2>{{name}}</h2>
<h2>{{sex}}</h2>
</div>
`,
data(){
return {
name: \'紫邪情\',
sex: \'女\'
}
}
}
const info = Vue.extend({
template: `
<div>
<h2>{{address}}</h2>
<h2>{{job}}</h2>
<!-- 这个组件中使用被嵌套的组件 -->
<person></person>
</div>
`,
data(){
return {
address: \'浙江杭州\',
job: \'java\'
}
},
// 基础组件嵌套 —— 这个组件中嵌套person组件
/*
注意前提:被嵌套的组件 需要比 当前嵌套组件先定义( 如:person组件是在info组件前面定义的 )
原因:因为Vue解析模板时,会按照代码顺序解析,如果定义顺序反了
就会出现:这里用到的组件 在 解析时由于在后面还未解析从而出现找不到
*/
components: {
person,
}
})
// 创建 vm 实例对象
const vm = new Vue({
// 指定控制的区域
el:\'#app\',
data:{},
// 2、注册组件 —— 由于info组件中 嵌套了 person组件,所以在这里只需要注册 info组件即可
components: {
info,
}
});
</script>
</body>
</html>
另一种嵌套:开发中玩的,我的快捷模板给那个div容器起的id值为app,是有用的
在开发中的嵌套是一个vm管理独一无二的app( 就是application 应用的意思 ),然后由app管理众多小弟
所以,现在来玩一下这种组件嵌套
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vm管app,app管众多组件</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<!-- 被 vm 实例所控制的区域 -->
<div id="app"></div>
<script>
// 去除浏览器控制台中的警告提示信息
Vue.config.productionTip = false;
// 1、定义组件
const person = {
template: `
<div>
<h2>{{name}}</h2>
<h2>{{sex}}</h2>
</div>
`,
data(){
return {
name: \'紫邪情\',
sex: \'女\'
}
}
}
const info = Vue.extend({
template: `
<div>
<h2>{{address}}</h2>
<h2>{{job}}</h2>
<!-- 这个组件中使用被嵌套的组件 -->
<person></person>
</div>
`,
data(){
return {
address: \'浙江杭州\',
job: \'java\'
}
},
components: {
person,
}
})
// 再定义一个app组件,用来管理其他组件
const app = {
// 这个app组件没有其他的东西,就是注册和使用被管理组件而已
components: {
// 有其他组件也可以注册在这里面,这里由于info管理了person,所以只注册info即可
info
},
template: `
<div>
<info></info>
</div>
`,
}
// 创建 vm 实例对象
const vm = new Vue({
// 指定控制的区域
el:\'#app\',
data:{},
// 由于组件被app管理,所以:只注册app组件即可
components: { app },
// 使用组件
template: `
<div>
<app></app>
</div>
`,
});
</script>
</body>
</html>
2.2.4、认识VueComponent()函数
1、来看一下组件到底是谁?
基础代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>认识VueComponent</title>
<script src="../../js/vue.js"></script>
</head>
<body>
<!-- 被 vm 实例所控制的区域 -->
<div id="app"></div>
<script>
// 去除浏览器控制台中的警告提示信息
Vue.config.productionTip = false;
// 1、定义组件
const person = Vue.extend({
template: `
<div>
<h2>{{name}}</h2>
<h2>{{job}}</h2>
<h2>{{address}}</h2>
</div>
`,
data(){
return {
name: \'紫邪情\',
job: \'java\',
address: \'浙江杭州\'
}
}
})
const app = {
components: {person},
template: `
<div>
<person></person>
</div>
`,
}
// 创建 vm 实例对象
const vm = new Vue({
// 指定控制的区域
el:\'#app\',
data:{},
components: {app},
template: `
<div>
<app></app>
</div>
`,
});
</script>
</body>
</html>
- 现在就来见一下组件的真身( 在前面玩this的时候说过,this指向的是:Vue实例 / 组件实例对象 ),因此:用this就可以知道组件的真身
既然知道了组件真身是VueComponent(),那么先去源码中看一下它,从而获取到一些对自己有用、能明白的信息
源码提取出来就是下面的样子
var Sub = function VueComponent (options) {
this._init(options); <!--里面的重要逻辑封装在了_init()中了,目前不要去看-->
};
return Sub
};
经过前面的分析和查看源码得出两个结论:
- 1、所有的组件指的都是VueComponent()
- 2、每一个组件都调用了VueComponent(),但是:它们都不一样( 源码中有嘛,每次都是创建了一个全新的sub,sub就是VueComponent(),最后把这个sub返回去了,验证一下嘛
- 但是:这里有一个有意思的东西,不了解原因的人很容易弄错,也是第一条说的组件就是指VueComponent(),从而会出现不了解的人认为:每个组件都是调了同一个VueComponent(),来看一下
- 这两个长得一模一样,所以就会让人误会,玩java的人看到这个肯定熟悉得不得了,这就是一个构造函数嘛,所以理解起来也更容易,构造函数,那就是Vue每次解析模板时( div容器使用的组件标签 ),Vue就会去帮忙创建对应的组件,调用了构造函数,怎么调用的?new出来的嘛,所以:这两个组件对象肯定不一样( 前面先验证是否一样就是为了注意这点,看起来一样,实质不一样 ,每个组件创建的都是全新的VueComponent(),得到的是一个全新的对象Sub )
- 同时上面说到,Vue解析模板时,会帮忙去创建VueComponent(),那么实质是谁去帮忙创建的?
- 答案就是创建组件时,里面的Vue.extend()去帮忙创建的,这不是我们程序员自己整出来的,看一下源码
- 但是:这里有一个有意思的东西,不了解原因的人很容易弄错,也是第一条说的组件就是指VueComponent(),从而会出现不了解的人认为:每个组件都是调了同一个VueComponent(),来看一下
VueComponent()小结
组件本质是一个名为VueComponent()的构造函数,且不是程序员自己定义的,是Vue.extend()生成的
我们只需要写组件标签(
<person></person>
或<person/>
) ,Vue解析组件标签时会帮我们创建组件的实例对象,即:Vue帮我们执行了new VueComponent( { options配置选项 } )- 注意点:每次调用Vue.extend(),返回的都是一个全新的VueComponent
关于this的指向问题
- (1)、在组件配置中:
- data函数、methods函数、watch中的函数、computed中的函数,它们的this均是【VueComponent实例对象】
- (2)、在new Vue()配置中:
- data函数、methods函数、watch中的函数、computed中的函数,它们的this均是【vue实例对象,即:前面玩的vm 】
- (1)、在组件配置中:
VueComponent实例对象,简称:vc( 或:组件实例对象 )
Vue实例对象,简称:vm
但是:vm和vc也有一个坑
观察结构会发现:vm和vc如出一辙,什么数据代理、数据监测等等,vm有的,vc都有,所以vm中的配置项在vc中都可以配置,但是:vm和vc不能画等号,它们两个不一样
- vm是Vue实例对象,vc是组件实例对象
- vm中可以使用el选项,而vc中不可以( 只要用el就报错 )
- 在vm中,data可以用函数式和对象式,但是在vc中data只能用函数式
- vm是大哥,vc是小弟,vc是vm的组件( 或者说:算上app,那么vc就是vm的后代 )
- vm和vc之间很多东西只是复用了而已- ( 这里说的复用,里面有大门道,vm和vc之间是有关系的,这里需要原型对象知识 —— 就一句话:函数肯定有prototype( 显示原型属性 ),而实例( 如:const person = vue.extend()中的person )肯定有 _ _proto _ _ ( 隐式原型属性 ),而这二者指向的是同一个对象:即,该实例的原型对象,而vc和vm之间就是通过这二者关联起来的
vm和vc之间的内置关系是:VueComponent.prototype._ _proto _ _ === Vue.prototype【这句话的验证自行在控制台输出查看,答案是:true】
- 图中:VueComponent的原型对象通过 _ _proto _ _理论上应该直接指向object的原型对象,但是:Vue做了巧妙的事情:就是让VueComponent的原型对象通过 _ _proto _ _指向了Vue的原型对象,这样做的好处就是:让组件实例对象 可以访问到 Vue原型上的属性、方法
以上的内容就属于非单文件组件相关的,接下来就看单文件组件,也是开发中会做的事情
2.3、单文件组件
- 就是只有一个文件嘛,xxxx.vue
- 而xxxx就是前面说过的组件命名
- 单个单词:全小写、首字母大写
- 多个单词:用 - 进行分割、大驼峰命名
- 而开发中最常用的就是:首字母大写和大驼峰命名
2.3.1、疏通单文件组件的编写流程
- 前提:如果自己的编辑器是vscode,那么就给编辑器安装vetur插件,然后重启vscode,这个插件就是为了能够识别xxxx.vue文件的;如果自己是用的IDEA编辑器来写的vue,那么安装了vue.js插件之后,不用安装其他的插件都可以的
2.3.1.1、创建xxxx.vue文件
- 这个创建的就是单文件组件,前面玩非单文件组件,不是有三板斧吗,对照来看
- 创建了xxx.vue之后,是一个空文件,里面要写的东西就三样(模板template、交互script、样式style ),里面内容也对照非单文件组件来看
<template> <div class="temp">
<!-- 这里面就是模板 以前在非单文件组件中用的template选项是怎么写的,这里面就是怎么写的-->
<h2>{{name}}</h2>
</div>
</template>
<script>
// 这里面就是交互( data、methods、watch、computed..... )
// 就是非单文件组件中的定义组件
/* const person = vue.extend({
// 这里就最好配置name选项了,一般都是当前创建的xxxx.vue中的xxxx名字即可
name: \'Person\',
data() {
return {
name: \'紫邪情\'
}
},
// 这里面还可以写什么methods、watch.....之类的
})
*/
// 但是:上面是对照非单文件组件来写的,在这个单文件中其实换了一下下
// 1、这个组件是可以在其他地方复用的,所以:需要把这个组件暴露出去,然后在需要的地方引入即可
/*
这里需要使用到js中模块化的知识
export暴露 import引入嘛
但是:export暴露有三种方式
1、分别暴露 export const person = vue.extend({ 配置选项 }),
就是在前面加一个export而已
可是:根据前面非单文件的知识来看,这个是可以进行简写的
export person {}
2、统一暴露 就是单独弄一行代码,然后使用 export { 要进行暴露的名字 },多个使用 , 逗号隔开即可
3、默认暴露( vue中采用的一种,因为引入时简单 ) export default 组件名{ 配置选项 }
但是:组件名就是当前整个文件,所以可以省略
默认暴露引入: import 起个名字 from 它在哪里
而其他的暴露方式在引入时会有点麻烦
*/
// 正宗玩法
export default {
name: \'Person\',
data() {
return {
name: \'紫邪情\'
}
},
// 再配置其他需要的东西也行 如:methods、watch、computed.....
}
</script>
<style>
/* 这里面就是template中的样式编写, 有就写,没有就不写 */
.temp{
color: purple;
}
</style>
- xxx.vue文件,如果使用的是vscode+vetur,那么上面的模板有快捷键可以用 :就是输入 <v 然后回车就可以生成了
2.3.1.2、注册组件到app中
- 前面玩过,vm管app,app管其他的小弟,所以需要一个app组件,创建一个app.vue
<template> <div>
<!-- 3、使用app管理的组件 -->
<person></person>
</div>
</template>
<script>
// 1、引入定义的person组件(要是有其他组件要引入那是一样的套路)
// 1Person.vue这个名字不正规啊,我只是为了排序才加了一个1
import person from "./1Person.vue"
export default {
name: \'App\'
// 2、注册引起来的组件
components: {person} // 完成了引入和注册之后,在这里面就可以用引入的组件了
}
</script>
<style>
/* app是为了管理其他所有的组件,所以这个style其实不写也行( 按需要来吧 ) */
</style>
2.3.1.3、将app和vm绑定起来
- 新建一个main.js文件,创建这个文件的目的:一是让app和vm绑定,二是浏览器并不能识别.vue文件,所以根本展示不了,因此:需要将.vue文件转成js文件,这样浏览器就能解析了【 当然:解析的门道没这么简单啊 】
// 1、引入app组件import App from "./2App.vue"
// 2、把app组件和vm进行绑定
new Vue({
// 这里面和以前一样写法,当然:这里的el值绑定的是容器id,怕误会改成root也行
el: \'#App\',
components: {App}
})
2.3.1.4、创建容器
- 前面app组件和vm绑定了,但是vm中指定的el值,它绑定的容器还没有啊,因此:创建index.html
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>创建el容器</title>
<!--
记得要引入js,而此时就需要引入两个js,一个是main.js,一个是vue.js
可是:在解析下面的容器时,可能会导致js渲染不及时出问题
因此:引入js最好放在下面容器的后面引入
-->
</head>
<body>
<div id="App">
<!--
2、使用app组件,可以在这里使用,也可以不在这里使用
直接在app.vue中使用template选项进行使用
-->
<App></App>
</div>
<!--
1、引入js
vue.js是因为:main.js中new vue()需要它,所以:先引入vue.js【 提前准备好嘛 】
其次再引入main.js
-->
<script src="../../../js/vue.js"></script>
<script src="./3Main.js"></script>
</body>
</html>
- 经过上面的操作之后,玩Vue单文件组件的流程也就完了,整体结构就是如下所示
- 而整个流程按照解析的逻辑来看就是如下流程
- 1、进入index.html,创建了div id = "App"容器,然后引入vue.js,再引入main.js
- 2、但是:引入main.js,去main.js里面开始解析时,发现:需要引入App.vue,所以:接着引入App.vue
- 3、进入App.vue,又发现需要引入Person.vue
- 4、将所有东西都引入完了之后,就可以依次进行渲染了( 逻辑就不说明了 ),而经过上面的逻辑梳理之后会发现:main.js就是入口,是从main.js开始引入,从而把其他的东西也给引入进来了
- 1、进入index.html,创建了div id = "App"容器,然后引入vue.js,再引入main.js
当然:以上的东西弄完之后,还启动不了,一启动就会报错
- 这是因为:浏览器不能解析ES6语法,这需要使用另外一个技术,脚手架来支持
2.3.2、认识脚手架 vue cli
cli全称: command line interface 即:命令行接口工具,但是:一般说的都是脚手架,正规名字说起来太官方、绕口
在vue官网有这个脚手架生态
2.3.2.1、使用nodejs配置脚手架
- 前提:保证自己的电脑有nodejs,玩后端的人要是不了解nodejs的话,就把它理解为服务器,低配版的tomcat,
- nodejs的配置很简单,官网进行下载、一直next
- 有个注意点:选择安装目录时,别把nodejs安装到系统C盘了,不然很大可能出现权限不足,无法操作的问题,特别是:如果自己的电脑没升级,还是家庭版的而不是专业版的,这种问题更常见
- 出现这种问题就需要切换到管理员身份运行cmd才可以进行安装vue-cli了,甚至有时会奇葩点:需要在管理员身份下运行npm clean cache –force
- 然后再进入到C盘的用户目录下的appdata/roaming下把一个叫做npm-cache的缓存文件删了,最后再用管理员身份运行npm clean cache –force清除缓存【 当然:npm clean cache –force不是绝对好用,还得看自己的另外配置 不多延伸了 】,经过上面的操作,把自己整疯了之后才可以安装vue cli脚手架
- 有个注意点:选择安装目录时,别把nodejs安装到系统C盘了,不然很大可能出现权限不足,无法操作的问题,特别是:如果自己的电脑没升级,还是家庭版的而不是专业版的,这种问题更常见
nodejs官网:https://nodejs.org/en/download/
LTS就是稳定版,而CURRENT就是更新版( 新特性就丢在这里面的,可能会出现bug,所以不推荐下载 )
其中下载msi和zip都可以,区别就是msi是直接帮你把环境变量配好了的,当然:也有其他的区别,而zip就是解压之后,自己进到目录下复制路径,然后配置在“系统环境变量”的path目录中即可,这些操作玩java的第一天就弄了jdk的环境变量,所以再熟悉不过了,而如果是前端人员,nodejs早学了,所以可以下滑到到后面全局安装vue cli那里,安装成功之后是如下效果
查看一下是否成功?
进入dos窗口( win+r,输入cmd回车 )
表明成功
但是:现在npm的配置和缓存文件都在C盘用户目录/appdata/roaming/npm 和 appdata/local/npm-cache中的
因此:我们需要去改动这两个地方( 知道了这两个目录,不用改也可以,后面什么事都可以不做的,对后续的操作也没影响 ,嫌找东西时麻烦就可以改 )
1、在安装的nodejs中新建node_global和node_cache两个文件夹( 前为全局配置路径,后为npm缓存路径 )
2、执行如下命令( 路径记得复制成自己的 ),另外记得用管理员权限打开命令行窗口
进行设置
C:\WINDOWS\system32>npm config set prefix "D:\install\Nodejs\node_global"
C:\WINDOWS\system32>npm config set cache "D:\install\Nodejs\node_cache"
检查是否成功
C:\WINDOWS\system32>npm config get prefix
D:\install\Nodejs\node_global
C:\WINDOWS\system32>npm config get cache
D:\install\Nodejs\node_cache
可见成功修改,但是:还需要做最后一步,去改环境变量( 使用msi安装是默认配好了的,但现在我们改动了配置,需要去重新弄一下 )
- 在改环境变量之前,在刚刚新建的node_global目录下,再新建一个node_modules目录
- 在改环境变量之前,在刚刚新建的node_global目录下,再新建一个node_modules目录
3、修改环境变量( 后端人员再熟悉不过,如果前端人员不明白的,直接计算机右键,选择属性,选择高级系统设置,选择环境变量就可以了【家庭版和专业版、win10和win7不一样,自行查找】 )
- 最后一路点OK即可,测试是否成功,可以选择安装一个vue包来测试
- 此时可能出现报一堆的ERROR,最后一行的大概意思就是让使用 root/ admin...用户( 也就是让用管理员运行dos窗口,再执行命令 )
报一堆ERROR错误的解决办法:本质是你安装时弄错了,文件权限不够 / 另外一种也是最常见的一种,就是明明都是正规步骤,但是就是不行,这是因为你自己本身登录的电脑用户权限不够【 自己买电脑之后,创建登录用户时操作有问题 】
想解决,此时:做一个操作即可,回到nodejs安装的根目录
右键选择属性、安全、高级
当然:要是自己的电脑在这个安全界面中,直接编辑权限,然后把“写入权限”√上是可以的,那就直接√上【 我说的是勾上时,不报错、直接出现一个加载过程 / 无任何报错提示的那种 ,若选择勾上、确认时系统有一个什么鬼提示来着,忘球了,反正有个提示就是不允许操作 】,要是不行就接着往后看
- 没有用户,点击添加之后,选择主体、在检索名称前面的框中:输入你当前登录用户名、检索即可有结果、最后确认是自己就可以了,这种情会直接看到权限选择,直接选完全控制 / 除这个以外的全勾上即可
确认之后,再使用npm install -g xxx就发现可以了
安装之后,在刚刚新建的node_global和node_cache中是有东西的
如果想要把全局配置恢复为初始化配置的话,也很简单,系统C盘用户目录/.npmrc的文件,删了就可以了
- 配置成功了nodejs之后,就可以使用npm指令了
- 但是:npm是国外的,我们拉取东西时就犹如隔了一道墙,很慢,因此:拉取淘宝的镜像,从而使用cnpm来代替npm指令,拉取淘宝镜像链接:
npm install -g cnpm --registry=https://registry.npm.taobao.org
或npm config set registry http://registry.npm.taobao.org
这两个都可以,如果因为自己电脑原因出现卡顿,进度条走得很慢、或不走了,那直接敲一下回车就可以了( 但:不是绝对好使,可能在你那边就不得吃 )- 这两个淘宝镜像,建议用前者,另外:从拉取镜像这里开始就一定要保证自己的网络流畅、电脑性能稍微好一点,不然很容易导致一是淘宝镜像拉取失败( 看起来成功了,但是一用就报cnpm不是内部命令,出现这种一是权限不够,需要使用管理员身份打开dos窗口【就是前面做的修改文件权限当白做了,但:配置没错啊,只是镜像拉取失败了】,二是cnpm没拉完整 ),要求网络的另一个原因就是后面安装脚手架时,要是网络和电脑不好,也很容易出现看起来成功了,但是:一用就发现vue不是内部指令,这种还是一个失败品
- 下图是我重新拉取一遍的效果
- 1、全局安装@vue/cli,指令:npm install -g @vue/cli
- npm 是nodejs的指令 拉取了淘宝镜像之后,就可以使用cnpm代替了
- install 就是安装的意思
- -g 是全局安装
- @vue/cli 是安装的东西
- 有个注意点:要是有人知道可以使用npm install -g vue-cli这样安装脚手架的话,可以用,没错的,但是:目前别这么安装( 它安装的脚手架是旧版本的,用这种方式安装的不能保证vue( 目前版本是1 — 3 )和vue-cli( 目前版本是1 — 4 )的版本很适合,所以后续使用一些命令时可能会出现版本不足的问题,让把版本升级,而使用@vue/cli安装的是最新版本
- 对于后端人员来说,这些指令太简单了,所以后续不说明了,下图是我重新安装了一次的结果
- 2、创建一个文件夹,并进入目录中,使用指令:vue create xxxx
- vue create 是cli3.x的命令,要是前面安装脚手架时是乱整的,就会发现:这个命令用不了,要是出现这样的话,那么执行一遍这个命令,会提示你:卸载以前的cli,然后执行什么命令安装cli
- xxx 就是要创建的项目名
- 出现如上图就说明在开始拉取依赖了
- 3、启动项目
- 想要退出启动的程序,一是直接点窗口右上角的×,二是按两次ctrl+c即可
2.3.2.2、分析cli构建的项目
- 使用vscode打开刚刚编译的项目【 ps:有些人是个人才,打开还整半天,1文件夹右键有一个open with code / 使用code打开,图标就是vscode的,没有的话,是安装vscode时,有一个界面是open with xxxx 的两个选择框没选,卸载、重装把那两个√打上就可以了 】
1、packpage-lock.json
2、package.json
- 以上就是基础的东西,接下来就对照前面手写的单文件组件思路来分析接下来的东西,那时说过:main.js是入口,所以cli脚手架程序就从main.js入手( 在cli中为什么它是入口?脚手架底层做的处理 )
- 1、main.js
- 2、引入了App.vue组件,那就接着分析App.vue组件
- 注意:
- assets目录是专门用来放静态资源的,如:png、mp3...( 后端的人就把这个目录当做是SpringBoot中的那个static目录 )
- components目录是专门用来放组件的( App.vue是一人之下【vm】万人之上【其他任何组件】,所以不在这里面 )
- 注意:
- 3、上面引入了helloword组件,而那里面就是一堆正常的组件写法
- 4、分析的差不多了,但是:还少了一个重要的东西,容器在哪里?
- 就在index.html中,而这个东西有一个专门的public目录来放
- 就在index.html中,而这个东西有一个专门的public目录来放
- 经过前面的分析之后,再结合上次写的单文件组件,就知道对应的东西写在哪里了
- 顺便说一下:vscode中启动vue程序,按ctrl + 飘字符( esc下面、tab上面的那个按键 )唤出控制台,后面的就知道怎么做了 做了修改之后,按ctril+s保存时会自动重新编译 )
- 1、main.js
2.3.2.3、认识render()函数
- 把前面编译好的例子改一下( 我的是把前面疏通流程的代码拷贝进来的 )
- 原因就是:代码中的一句话
- 那就去看一下vue到底有哪些版本?按住ctrl+鼠标点引入的vue哪里,点vue就进去了
点开它的包说明:就发现引入的是dist/vue.runtime.esm.js
随便选择一个右键在资源管理器中显示,就可以看到文件大小( 可以和vue.js对比,就少了100kb左右而已,少的就是模板解析器,但是:少的这部分用处很大 )
vue为什么要搞出这么多版本?
- 这是因为vue其实就是将webpack进行了封装,然后添加了一些技术,从而搞出来的,所以webpack在进行打包时会将.vue转成.js从而实现渲染( 后端人员不懂webpack的,就粗暴的把它当做是maven中的install打包,当然:compile编译等等这些指令功能也在vue中有相同的效果的实现机制 )
- 而程序编写完了之后,webpack本身就支持将.vue转成.js,那使用webpack打包时,模板解析器就不应该出现了( 模板解析器就是编写时解析而已 ),所以真实打包时如果还要有模板解析器就出现一个骚气的事情,举个例子:去做某事
- 整出那么多版本的原因就知道了呗,减少程序体积、提高性能嘛
- 那就去看一下vue到底有哪些版本?按住ctrl+鼠标点引入的vue哪里,点vue就进去了
- 回到前面报的错,怎么解决?控制台已经把答案给的很明确了
- 1、使用包含模板解析器的vue就可以了
- 2、使用render()函数实现模板解析器的效果
- 1、使用包含模板解析器的vue最简单
- 引入的vue有问题,那就改一下嘛
- 引入的vue有问题,那就改一下嘛
- 2、使用render()函数来实现解析template的功能
- 知道了render()的结构,那就去实现解析template的功能
- 然后兰姆达表达式简写不就成原来的样子了吗
- App就是h2,因为:App是一个组件,使用时就是
<App/>
或<App><App>
- 这个render()函数也就在vm绑定容器时会用到,其他地方见都见不到的
- App就是h2,因为:App是一个组件,使用时就是
- 然后兰姆达表达式简写不就成原来的样子了吗
- 知道了render()的结构,那就去实现解析template的功能
2.3.2.4、关闭语法检测
- 官网中有,改cli的全局配置也是一样的套路
- 官网里面就是说新建一个vue.config.js的文件,这个文件必须和package.json是同级目录,然后要配置东西时,找对应的配置项,然后复制粘贴对应的内容( 或改动一点自己要的配置项即可 )
- 关闭语法监测,就是名为lintOnSave的配置项罢了
- 创建vue.config.js文件
- 创建vue.config.js文件
- 经过上面的操作之后,就算定义一个变量,然后后面一直没用这个变量也不会导致项目启动不了了,否则:使用npm run serve时,就会报错,导致启动不了
- 而创建这个vue.config.js文件能够修改cli的配置是因为:cli是在webpack的基础上做出来的,而webpack是在nodejs的基础上整出来的,因此:程序最后是将自己写的vue.config.js去和webpack中的进行了合并,从而就成功了
- 另外:注意点
- cli中不是什么都可以修改的,下图这些文件夹 / 文件名最好都别改( 是名字别改啊,没这么傻吧^ _ ^ )
- 想要重新改动,就在刚刚新建的vue.config.js中配置即可,但是注意:
- vue.config.js每一次更新都要使用npm run serve重新启动项目,否则不生效
- vue.config.js中不可以说:不用了加个注释,然后等后面用的时候再解开注释,这种是不行的,要么就配置,要么就不配置,否则:启动不了项目
2.3.3、认识ref属性
- 这个属性是用来给“元素”或“子组件“注册引用信息( 也就是id属性的替代者 ),这个小东西很重要,关系到后续组件与组件之间的通信
我重新复制了一份src文件夹,用的时候把名字改回来就可以了( 需要哪一个就把哪一个改为src,然后执行npm run serve
就行了 )
运行效果如下:
现在有一个需求:获取下图中的DOM结构
- 使用传统js来操作的话,就是
document.getElementById
进行获取,但是:Vue中提供得有ref属性来进行操作:ref属性用来给“元素”或“子组件“注册引用信息( 也就是id属性的替代者 ),所以来见识第一个“元素”注册引用信息( 在HTML元素中这个ref属性就和id属性是一样的效果 ) - 第二种:ref属性是在子组件上的
- 这种很重要,后面组件与组件之间交互的基础
- 但是:这种和id就不同了,id是直接获得了子组件的DOM结构,而ref是获得了组件本身VueComponent
ref属性小结
- 被用来给元素( id的替代者 )或子组件注册引用信息
- 应用在HTML标签上获取的是真实DOM元素,应用在组件标签上获取的是组件实例对象( vc )
- 使用方式:
- 做标识:
<h1 ref="xxx">......<h1>
或<Person ref="xxx"><Person>
- 获取:this.$refs.xxx
- 做标识:
2.3.4、props配置-获取外传数据
- 组件中的props配置就是为了获取从外部传到组件中的数据
- 这个东西很有用,后续玩子传父、父传子就需要这个东西,而且开发中这个东西会经常看到
2.3.4.1、只接收数据
Person.vue组件编写内容
<template> <div>
<h2>{{name}}</h2>
<h2>{{sex}}</h2>
<h2>{{age}}</h2>
<h2>{{job}}</h2>
<h2>{{address}}</h2>
</div>
</template>
<script>
export default {
name: \'person\',
// 使用props配置,使这个Person组件中的数据从外部传进来( 封装的思想来咯 )
// 第一种方式:只接收数据即可(数组写法) - 此种方式:接收的数据统统都是字符串
props: [\'name\',\'sex\',\'age\',\'job\',\'address\']
}
</script>
App.vue组件编写内容
<template> <div>
<h1 ref="content">欢迎来到对抗路,对手信息如下</h1>
<!-- 使用组件 并 传入数据 -->
<Person name="紫邪情" sex="女" age="18" job="java" address="浙江杭州"/>
</div>
</template>
<script>
import Person from "./components/Person.vue"
export default {
name: \'App\',
components: {Person},
}
</script>
ctrl+s重新编译
效果如下
2.3.4.2、接收数据 + 数据类型限定
- 至于限定类型有哪些? 可以是下列原生构造函数中的一种
String
、Number
、Boolean
、Array
、Object
、Date
、Function
、Symbol
、任何自定义构造函数、或上述内容组成的数组
2.3.4.3、接收数据+限定类型+数据有无接收的必要+数据默认值
- 这个东西,玩java的人看起来很熟悉,和ElasticSearch中的mapping映射很像
2.3.4.4、处理外部传入数据类型问题
- 问题就轻轻松松解决了
2.3.4.5、解决props接收数据之后,修改它的值
- props配置中不是什么属性名的值都可以接收的,如:key、ref
- 意思就是:key不能作为props接收的数据,原因就是因为:key这个属性被Vue给征用了,Vue底层需要使用diff算法嘛,它用了这个key关键字,所以我们不可以用它
回到正题,props接收了数据怎么修改它?
- 首先要知道,props被底层监视了的,所以它的东西只可以接收,不可以修改,想要接收了数据,再修改它,我们就需要借助data,中转一下
- 先来看不中转,然后修改props中数据的下场
- 使用data中转,从而修改数据
2.3.4.6、props配置总结
功能:让组件接收外部传进来的数据
(1)、传递数据
<Person name="xxxx">
(2)、接收数据
1)、只接收
- props: [\'name\']
2)、接收数据 + 数据类型限定
props: {
name:String
}
3)、接收数据 + 数据类型限定 + 必要性限制 + 数据默认值
props: {
type:String,
required:true,
default:\'紫邪情\' 注:一个数据字段不会同时出现required和defautle
}
注意:props中的数据是只读的,Vue底层会监测对props的修改,如果进行了修改,就会发出警告
- 如果业务需要修改,则:把props中的数据复制一份到data中,然后去修改data中的数据就可以了
- 须知:vue中优先使用props中的数据,然后再使用data中的数据( 可以使用data中的名字和props中的名字一样,然后去渲染,发现渲染出来的数据是props中的 )
2.3.5、mixin混入 / 混合
- 这个东西就是把多个组件中共同的配置给抽取出来,然后单独弄成一个js文件,使用一个对象把相同配置给封装起来,然后在需要的组件中引入、使用mixins配置进行使用即可
- 这种思想后端的人再熟悉不过了,工具类的编写不就是这么回事吗
2.3.5.1、使用
基础代码
在上面的代码中,methods中的代码是相同的,因此:使用mixin混入来进行简化,也是三板斧而已
- 1、新建js文件( 名字根据需要取即可 )
- 2、在需要的组件中引入抽取的代码和利用mixins配置进行使用
- 3、运行效果
但是:mixin混入有一些注意点
- 1、除了生命周期,如果其他配置是在mixin中定义了,同时在组件中也定义了,那么:优先使用的是组件中自己定义的( 无论二者相同与否都一样 )
- 2、如果在mixin中定义了生命周期钩子函数,那么:优先使用mixin中的钩子函数
- 如果二者不同,那么就会造成二者中定义的都会被调用
- 如果二者不同,那么就会造成二者中定义的都会被调用
另外:mixin混入是支持全局配置的,不过这种操作不当会出现问题,因此:目前不建议用,需要时再玩吧,思路如下:
- 1、一样的创建js文件
- 2、在App.vue中引入
- 3、在App.vue中使用vue.mixin( 暴露对象1 ) 、vue.mixin( 暴露对象2 ).......
- 使用了这三板斧之后,就可以实现全局配置了
2.3.5.2、mixin混入总结
功能:把多个组件共同的配置提取成一个混入对象
使用方法:
1、定义混入,如:
暴露方式 const 对象名 {
data(){......},
methods:{........},
........
}
2、在需要的组件中引入混入
3、使用混入,如:
- 1)、局部混入:mixins: [ xxxxxx , ......... ] , 注意:这里必须用数组
- 2)、全局混入:Vue.mixin( xxxxx )
2.3.6、插件
- 这个东西的作用很大,它可以合理的增强Vue
使用,也简单,还是三板斧
- 1、创建js文件( 包含install()方法的一个对象 )
- 2、引入插件
- 3、使用插件
2.3.6.1、玩一下插件
基础代码效果
1、创建一个包含install()方法的对象的js文件
2、在main.js中引入、使用插件
3、效果如下
- 可以得知:创建的插件中传递的那个参数Vue就是vm( Vue实例对象 )的缔造者 —— vue构造函数
- 得到上面哪那个结果就很重要了,试想:我们使用这个构造函数做过什么事?
- 自定义全局指令 Vue.directive
- 定义全局过滤器 Vue.filter
- 定义全局混入 Vue.mixin
- ........
- 把这些东西放到创建插件的install()中可行?它接受的参数就是Vue嘛
正宗玩法
- 1、创建包含install()方法的对象的js文件
- 2、在main.js中引入插件、应用组件
- 3、使用插件中的东西
- 4、效果如下:
当然:我们也可以给插件中传东西进去
2.3.6.2、插件总结
功能:用于增强Vue
本质:是包含install()方法的一个对象的js文件,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据
插件的玩法:
1、定义插件:
// 1、创建插件 export default 是自己选择的暴露方式
export default {
install(Vue,[ other params ]){
// 定义全局过滤器
Vue.filter( ..... ),
Vue.directive( ...... ),
Vue.mixin( ....... )
.........
}
}
2、在main.js中引入插件
3、在main.js中向Vue应用插件 Vue.use( 插件名 )
[ 4、使用插件中定义的东西 ] ———— 可有可没有,看自己的代码情况
这里注意一个东西:定义插件中的install()第一个参数是Vue,即:vm的缔造者,Vue构造函数( 这里可以联想原型对象,也就是前面说的vm和vc的内置关系:
VueComponent.prototype._ _proto _ _ === Vue.prototype
,这也就是说在Vue身上加点东西,那么:vm和vc都可以拿到,如:Vue.prototype.$myMethod = function(){ ...... }
Vue.prototype.$myProperty = xxxx
prototype路线是加东西
_ _proto_ _路线是取东西
2.3.7、scoped局部样式
- 作用:让样式在局部生效,防止冲突
- 写法:
<style scoped>
假如有两个组件,里面都用了同一个class类名,但是做的style却是不一样的
此时如果把两个class名字改成一样呢?开发中样式多了这种事情是在所难免的
凭什么就是Person2.vue组件中的样式优先?
- 这和App.vue中引入组件的顺序有关
- 不然:把组件引入的顺序换一下就发现变了
那上述样式冲突了怎么解决?
- 答案就是使用scoped限制作用域( 后端人员,这个东西熟悉得很,maven中依赖的作用域,是一样的效果 )
- 这个小技巧在开发中会经常见到
当然:style标签不止支持scoped属性,还可以用其他的
另外:less需要less-loader支持,所以需要安装less-loader,但是:有坑( 版本的问题 )
cli中的webpack版本
安装适合cli的webpack的less-loader版本
最后还有一个问题:scoped使用在App.vue中就会发生很诡异的事情
- App.vue是大哥,所以这里面的style会全局生效( 也就是多组件都在使用的样式,就可以提到App.vue中写,然后在其他需要的组件中使用即可 )
- 但是:如果App.vue中style使用了scoped,那么就会导致:样式只在App.vue中有效,那么:其他组件中想要用,那对不起,管不了,最后页面就会出现诡异的事情 —— 不是自己写的样式的样子
- 所以:App.vue中最好别用scoped属性,而其他组件中最好都加上scoped属性
2.3.8、组件化应用应该怎么去写?
实例:实现如下的效果( 就是一个人名录入,然后可以对名字做一点操作罢了 )
- 组件编写流程( 基本上都是一样的套路 ),接下来按照套路去弄就可以了
2.3.8.1、分析结构 / 拆分组件
根据页面结构来看,可以拆分成如下的结构:
- 1、外面大的框就是一个组件 —— 也就是App.vue父组件,而App组件中又包含的如下组件:
- 1.1、输入框是一个组件( 子 )
- 1.2、人名的展示框是一个组件( 子 ,却是下面两个的“父” )
- 1.2.1、然后发现展示框里面又有每一个人名组件( 子 )
- 1.2.2、还有一个全选 / 显示已选人数的组件( 子 )
2.3.8.2、创建对应组件并编写内容
1、创建并编写组件对应内容( 统称编写静态组件 )
1)、App组件
(1)、HTML结构
<template>
<div id="root">
<div class="name-container">
<div class="name-wrap">
<NameHeader></NameHeader>
<NameList></NameList>
<NameFooter></NameFooter>
</div>
</div>
</div>
</template>
<script>
import NameHeader from "./components/NameHeader.vue"
import NameList from "./components/NameList.vue"
import NameFooter from "./components/NameFooter.vue"
export default {
name: \'App\',
components: {NameHeader,NameList,NameFooter}
}
</script>
(2)、CSS样式 + 后续需要的通用样式
body{
background: #fff;
}
.btn {
display: inline-block;
padding: 4px 12px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
text-align: center;
vertical-align: middle;
cursor: pointer;
box-shadow: inset 0 1px rgba(255,255,255,0.2),0 1px 2px rgba(0, 0, 0, 0.05);
border-radius: 4px;
}
.btn-danger {
color: #fff;
background-color: #da4f49;
border: 1px solid #bd362f;
}
.btn-danger:hover {
color: #fff;
background-color: #bd362f;
}
.btn:focus {
outline: none;
}
.name-container {
width: 600px;
margin: 0 auto;
}
.name-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
2)、输入框组件
(1)、HTML结构
<div class="name-footer">
<label>
<input type="checkbox">
</label>
<span>
<span>已选择0</span> / 共计2
</span>
<button class="btn btn-danger">清除已选人员</button>
</div>
3)、人名展示框
(1)、HTML结构
<template>
<NameObj></NameObj>
</template>
<script>
import NameObj from "./NameObj.vue"
export default {
name: \'NameList\',
components: {NameObj}
}
</script>
(2)、CSS样式
/* #region list */
.name-main {
margin-left: 0px;
border: 1px solid s#ddd;
border-radius: 2px;
padding: 0px;
}
.name-empty {
height: 40px;
line-height: 40px;
border: 1px solid #ddd;
border-radius: 2px;
padding-left: 5px;
margin-top: 10px;
}
/* #endregion */
4、每个人名展示
(1)、HTML结构
<template>
<ul class="name-main">
<li>
<label>
<input type="checkbox"/>
<span>xxxxx</span>
</label>
<button class="btn btn-danger" style="display:none">删除</button>
</li>
</ul>
</template>
<script>
export default {
name: \'NameObj\',
}
</script>
(2)、CSS样式
/* #region item */
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
li label {
float: left;
cursor: pointer;
}
li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: 1px;
}
li button {
float: right;
display: none;
margin-top: 3px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
/* #endregion */
运行效果如下:
- 自此:静态组件编程就搞定,后续就可以做数据的动态绑定和交互这些了
- 将纯HTML + CSS + JS转成组件化开发也是一样的套路,流程如下:
- 1、把整个HTML结构放到App.vue组件的template模板中
- 2、把所有的CSS放到App.vue组件的style中
- 3、有JS的话,那么把js文件创好,然后引入到App.vue组件中
- 4、开始去分析结构,然后拆分成组件,之后把对应的内容放到对应组件中,最后做后续的动态数据绑定、交互即可
2.3.8.3、动态数据绑定
按照分析,要展示的数据是一堆数据,而数据显示的地方是NameList,所以:data数据就放到NameList中去。本实例中数据放到这里有坑啊,但是:先这么放,后续遇到坑了再调整,所以改一下源码
- 数据是弄好了,但是:真正展示数据的是NameObj组件来显示出来的,而NameObj是NamelList的子组件( 这就是:父传子 ),这种就需要借助props配置项( 从外向内传嘛 ),所以:开始操作
1、父传子
2、获取输入的内容并添加到显示的顶部 —— 和后续知识挂钩的重点来了
- 输入框组件是App组件的子组件,而数据展示是NameList组件中的NameObj组件,即:现在关系就是如下的样子
- 上面这种就是不同组件之间的通信情况,现在来了解原生的解决办法
3、原生的不同组件通讯
- App.vue是大哥,用它做文章,这样就变成了App这个父组件和输入框以及Namelist这两个子组件之间的关系了
- 第一步:将data搬到App组件中去并传给NameList数据展示组件
- 然后NameList数据显示区再传给数据显示组件
- 这样父传子、子传孙....这样就串通一条路了( 即:下图右边部分 )
- 然后NameList数据显示区再传给数据显示组件
- 第二步:将输入框组件中的数据收集起来,并传给父组件( 这就是子传父 )
- 将数据传给父组件 —— 开始子传父
- 子传父的技巧就是:父组件传给子组件一个函数( props的变样版,传的不是对象、key-value,而是整一个函数传过去 )、然后子组件利用props接收到函数之后调用一下( 把传递数据当做参数 ),那么父组件中的函数的参数就是要传递的数据了
- 上图id是使用random()生成的随机数啊,这有弊端的,数字有穷尽的时候,所以:严格来说用uuid、身份证号、电话号码......作为id最好
4、将子组件传递的数据添加到数据栏的顶部去
2.3.8.4、交互编写
1、实现选择和数据的改变
- 1)、最简单粗暴的方式 —— 但是:不建议用
- 成功是成功了,但是:说了不建议用,因为:这种方式违背了Vue的设计( 但是:开发中又喜欢用,简单实用嘛 )
- 违背了Vue的设计是因为:props在底层是被检测了的,Vue不支持去修改它的东西,但是:按上述的方式做了之后,却会发现:并不会报错,这是因为:修改的是值和对象的区别
- 成功是成功了,但是:说了不建议用,因为:这种方式违背了Vue的设计( 但是:开发中又喜欢用,简单实用嘛 )
- 2)、按照逻辑老实编写
- 这种实现方式的思路就是:在页面中点击 / 改变选择框时,拿到这条数据的id,然后利用id去所有的数据中遍历,找到对应的这条数据,最后改变这条数据isCheck的值即可
- 下面的操作也是一个父传子的使用过程
- 这里有一句话:数据在哪里,对数据的操作( methods )就在哪里
2、实现每条数据的删除功能
- 1)、先把样式解开,让鼠标悬浮时删除按钮可见
- 2)、实现数据与删除按钮交互( 还是子传父的套路 )
- 实现逻辑简单:拿到要删除数据的id,然后去众多数据中把要删除数据给过滤掉不显示即可( 逻辑删除 )
3、实现底部的已选择人数和总计人数功能
3.1、最原生的方式
- 1)、父传子 —— 传递persons这个数据
3.2、使用数组的reduce()这个API,这个API专做数据统计的
- 认识一下reduce()
- reduce()最终的返回值是:程序执行的最后一次的nextValue值
- 使用reduce()实现功能
接下来就只剩下底部的全选和清除已选这两个功能了
4、实现全选交互和清除已选人员功能
4.1、实现全选交互( 子传父 + 计算属性使用技巧 )
- 上面这个全选使用分步利用子传父实现每一步也是可以的,只是有点复杂罢了
4.2、清除已选人员
- 这个的思路更简单了,就是查看页面中的数据哪些的isCheck为true,然后过滤掉这些数据即可( 实现方式一样简单,也是子传父 )
2.3.8.5、组件化开发流程总结
组件化编写流程
- 1、拆分静态组件:组件要按照功能点拆分,命名不要和HTML元素名冲突
- 2、实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用
- 一个组件在用:把数据放到组件自身即可
- 一些组件在用:把数据放到它们共同的父组件上【 这也叫状态提升 】
- 3、实现交互:从绑定事件开始
props配置总结
- 适用于以下过程
- 1、父组件 ——> 子组件 通信
- 2、子组件 ——> 父组件 通信
v-model总结
- 使用v-model时要切记:v-model绑定的是值,但是:这个值不能是props中传递过来的值,因为:props底层被Vue监测了的,不允许修改
- 注:props中传过来的若是对象类型的值时,虽然修改"对象中的属性"时Vue不会报错,但是:不建议用
2.3.9、下一篇链接
- https://www.cnblogs.com/xiegongzi/p/15875808.html
以上是 Vue2技术整理2 - 核心篇 - 更新完毕 的全部内容, 来源链接: utcz.com/z/378958.html