最近在学习Vue,下面是学习过程中总结了一些基本的知识点
Vue
一. 基本知识
1. 实例化
var app = new Vue({
el: '#app', //绑定到元素上
data: {
message:'hello world'
},
filters:{
filterName1:function(){},
filterName2:function(){}
},
methods:{
methodName1:function(){},
methodName2:function(){}
},
//生命周期钩子
created:function(){
//未挂载到dom之前触发
},
mounted:function(){
//挂载到dom后触发
},
beforeDestroy:function(){
}
})
2. 过滤器
{{ data中的变量名 | filter中的过滤器名 }}
3. 指令和事件
v-text:解析文本,和{{ }}作用一样
v-html:解析html
v-bind:动态更新HTML元素上的属性
v-on:绑定事件监听器
v-bind语法糖:冒号 :
v-on语法糖:@
-
v-bind的作用,以及v-bind的变量语法,数组语法,对象语法:
- v-bind通常用来绑定属性的,格式是v-bind:属性名 = "值",简写:属性名 = "值"
- 变量语法:v-bind:class = "变量",变量形式 ,这里的变量的值,通常是在css定义好的类名;
- 数组语法:v-bind:class= "[变量1,变量2]" ,数组形式,其实跟上面差不多,只不过可以同时绑定多个class名;
- 对象语法:v-bind:class = {classname1:boolean,classname2:boolean},对象形式,这里的classname1(2)其实就是样式表中的类名,这里的boolean通常是一个变量,也可以是常量、计算属性等,这种方法也是绑定class最常用的方式。
4. VUE内置指令
-
v-cloak : 解决页面没加载完的时候出现类似{{ msg }}等变量名的现象,一般和display:none一起使用
<style> [v-cloak]:{ display-none; } </style> ------------------------- <p v-cloak> {{ msg }} </p>
-
v-once:只在页面中渲染一次,改变变量的值也不会重新渲染
<p v-once> {{ msg }} </p>
-
条件指令:v-if
v-if : 后面接的是等号,等号后面的内容必须是布尔值,布尔值为true则渲染,否则不渲染
v-else
v-else-if
-
例:
<p v-if = '6>3'>{{ apple }}</p> <p v-else-if = '9<6'> {{ banana}} </p> <p v-else> {{ orange }} </p>
v-if的弊端:Vue在渲染元素时,出于效率考虑,会尽可能的复用已有的元素而非重新渲染,因
此会出现乌龙解决方法:加key,唯一,提供key值可以来决定是否复用该元素
-
v-show:只改变display属性
-
v-if和v-show的区别:
v-if:实时渲染:页面显示就渲染,不显示就移除
v-show:元素始终存在于页面中,只是改变了display属性
-
-
v-for:
-
遍历多个对象:data 里面是一个数组
<div id='app'> <ul> <!-- intm in items --> <li v-for="fruit in fruits">{{ fruit.name }}</li> </ul> <ul> <!-- 带索引的写法 --> <li v-for="(fruit,index) in fruits">第{{ index }}个 {{ fruit.name }}</li> </ul> </div> <script> var app = new Vue({ el: '#app', data: { //这里是一个数组 fruits: [ {name: 'apple'}, {name: 'banana'}, {name: 'orange'} ] } }) </script>
-
-
遍历一个对象的多个属性
<div id='app'> <span v-for='value in fruits'>{{ value }}</span> <!-- 带v-k-i的写法:value key index (外开) --> <p v-for="(value,key,index) in fruits2"> value:{{value}}<br> key:{{key}}<br> index:{{index}} </p> </div> <script> var app = new Vue({ el: '#app', data: { //这里是一个对象 fruits: { fruit1: 'apple', fruit2: 'banana', fruit3: 'orange' } } }) </script>
v-model表单
5. 计算属性
-
基础例子
<div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // 计算属性的 getter reversedMessage: function () { // `this` 指向 vm 实例 return this.message.split('').reverse().join('') } } })
-
计算属性的 setter
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
在赋值的时候会触发set函数,把新赋的值以参数的形式传递进去
// ... computed: { fullName: { // getter get: function () { return this.firstName + ' ' + this.lastName }, // setter set: function (newValue) { var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } // ...
现在再运行
vm.fullName = 'John Doe'
时,setter 会被调用,vm.firstName
和vm.lastName
也会相应地被更新。
6. 数组更新、过滤与排序
改变数组的一系列方法:
- push() 在末尾添加元素
- pop() 将数组的最后一个元素移除
- shift() 删除数组的第一个元素
- unshift():在数组的第一个元素位置添加一个元素
- splice() :可以添加或者删除函数—返回删除的元素
三个参数:- 第一个参数 表示开始操作的位置
- 第二个参数表示:要操作的长度
- 第三个为可选参数:
• sort():排序
• reverse()
两个数组变动vue检测不到:
- 改变数组的指定项
- 改变数组长度
过滤:filter
解决方法:
改变指定项: Vue.set(app.arr,1,”car”);
app.arr.splice(1): 改变数组长度
二. 组件
组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。
1. 组件用法
-
全局注册
Vue.component('component-name',{ template: '<div>组件内容</div>' }) //优点:所有Vue实例都可以使用 //缺点:权限太大,容错率低
-
局部注册
var app = new Vue({ el: '#app', data:{}, components: { 'component-name': { template: '<div>组件内容</div>' } } })
-
注意事项:
组件名用横杆命名法,不能用驼峰命名法
template中的内容必须被一个DOM元素包起来
在组件的定义中,除了template,还可以有data、methods、computed选项
-
data必须是一个方法
data: function(){ return { message: 'hello world' } }
2. props父级向子级传递数据
在组件中使用props从父组件接收参数,props中定义的属性,在组件送可以直接使用
props来自父级,而data中return的数据是自己组件本身的数据,两种数据的作用域都是组件本身,可以在template、methods、computed中直接使用
props的值有两种,一种是字符串数组,一种是对象
-
可以使用vbind动态绑定父组件来的内容
<div id="app"> ---用v-bind传递数据(需要回车)-------------------------<br> <input type="text" v-model.lazy="parentMsg"> <bind-component v-bind:msg='parentMsg'></bind-component> </div> var app = new Vue({ el: '#app', data: { count: 0, parentMsg: '这是来自父级的数据' }, components: { 'bind-component': { props:['msg'], template: '<div>{{ msg }}</div>' } } })
3. 单项数据流
props传递数据是单向的,父级数据的变化会传递给子级,反之就行不通了
单向数据流可以避免子组件无意中修改父组件状态
-
应用情景:
-
第一种:父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域
下可以随意使用和修改。<div id="app"> <my-component msg="来自父级的数据"></my-component> </div> ---javascript--------------------- <script> var app = new Vue({ el: '#app', data: {}, components: { 'my-component': { props: ['msg'], template: '<p>{{ newMsg }}<p>', data: function () { return { //在data中保存下来 newMsg: this.msg } } } } }) </script>
-
第二种:需要被转变的原始值传入,通过props获取,通过计算属性进行转换
<div id="app"> <input type="number" v-model="width"> <computed-component :wth='width'></computed-component> </div> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> var app = new Vue({ el: '#app', data: {width:10}, components: { 'computed-component': { props: ['wth'], template:'<div :style="style"></div>', //用计算属性转换传入的值 computed: { style: function(){ return { width: this.wth + 'px', height: '100px', background: 'red' } } } } } }) </script>
-
4. 组件命名注意事项
- 在html中, myMessage 和 mymessage 是一致的,因此在组件中的html
中使用必须使用kebabcase(短横线)命名方式。在html中不允许使用驼
峰!!!!!! - 在组件中, 父组件给子组件传递数据必须用短横线。在template中,必
须使用驼峰命名方式,若为短横线的命名方式。则会直接保错。 - 在组件的data中,用this.XXX引用时,只能是驼峰命名方式。若为短横线
的命名方式,则会报错。
5. 数据类型验证
-
验证的 type 类型可以是:
- String
- Number
- Boolean
- Object
- Array
- Function
Vue.component ( ‘ my-compopent ’, { props : { //必须是数字类型 propA : Number , //必须是字符串或数字类型 propB : [String , Number] , //布尔值,如果没有定义,默认值就是 true propC: { type : Boolean , default : true }, //数字,而且是必传 propD: { type: Number , required : true }, //如果是数组或对象,默认值必须是一个函数来返回 propE: { type : Array, default : function () { return [] ; } }, //自定义一个验证函数 propF: { validator : function (value) { return value > 10; } } } });
三. 组件通信
1. 自定义事件
用于:子组件给父级传递数据
子组件用$emit ( '父组件中事件名' , 要传递的数据 ) 来触发事件 ,父组件用@'父组件中事件名'='触发的函数'来 监昕子组件的事件,触发的函数的参数即为子组件传递来的数据
第一步:自定义事件
第二步:在子组件中用$emit触发事件,第一个参数是事件名,后边的参数是要传递的数据
第三步:在自定义事件中用一个参数来接受
<div id="app">
您的余额是:{{ acount }}<br>
<my-component :acount="acount" @change-acount='handleAcount'></my-component>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
acount: 2000
},
methods:{
handleAcount:function(value){
this.acount = value
}
},
components: {
'my-component': {
props:['acount'],
template: `<div>
<button @click="addAcount">+1000</button>
<button @click="reduceAcount">-1000</button>
</div>`,
data: function(){
return {
count: this.acount
}
},
methods:{
addAcount: function(){
this.count += 1000
//注意这里$emit的参数
this.$emit('change-acount',this.count)
},
reduceAcount: function(){
this.count -= 1000
this.$emit('change-acount',this.count)
}
}
}
}
})
2. 在组件中使用v-model
在组件中使用v-model 其实是一个语法糖,这背后其实做了两个操作
- v-bind 绑定一个 value 属性
- v-on 指令给当前元素绑定 input 事件
$emit('input',value)的代码,这行代码实际上会触发一个 input事件, ‘input’后的参数就是传递给v-model绑定
的属性的值
<div id="app">
您的余额是:{{ acount }}<br>
<!-- <my-component :acount="acount" @change-acount='handleAcount'></my-component> -->
<!-- 下面使用v-model -->
<my-component :acount="acount" v-model='acount'></my-component>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
acount: 2000
},
components: {
'my-component': {
props:['acount'],
template: `<div>
<button @click="addAcount">+1000</button>
<button @click="reduceAcount">-1000</button>
</div>`,
data: function(){
return {
count: this.acount
}
},
methods:{
addAcount: function(){
this.count += 1000
// 这里触发的是input事件
this.$emit('input',this.count)
},
reduceAcount: function(){
this.count -= 1000
this.$emit('input',this.count)
}
}
}
}
})
</script>
3. 非父组件之间的通信---bus中介
用于两个组件之间的通信,(非父子关系),可以在根组件中用一个空的Vue对象作为中介,一个组件中监听该中介的自定义事件,另一个组件中触发该自定义事件并传递数据
<div id="app">
<acomponent></acomponent>
<bcomponent></bcomponent>
</div>
<script>
Vue.component('acomponent', {
template: '<button @click="handle">点击向B组件传递数据</button>',
data: function () {
return {
msg: '我是来自A组件的数据'
}
},
methods: {
handle: function () {
// 触发根组件的bus中的method1事件
this.$root.bus.$emit('method1', this.msg)
}
}
})
Vue.component('bcomponent', {
template: '<div>{{ msg }}</div>',
data: function () {
return {
msg: '这是B组件'
}
},
created: function () {
// 对根组件bus监听method1事件
this.$root.bus.$on('method1', (value)=> {
this.msg = value
})
}
})
var app = new Vue({
el: '#app',
data: {
bus: new Vue()
}
})
</script>
4. 父链和子链
父链:this.$parent
子链:this.$refs.索引
提供了为子组件提供索引的方法,用特殊的属性ref为其增加一个索引
<div id="app">
<button @click='clickA'>A子组件</button>
<button @click='clickB'>B子组件</button>
<son-a ref='a'></son-a>
<son-b ref='b'></son-b>
</div>
<script>
var app = new Vue({
el: '#app',
data: { msg: '来自父组件的msg' },
methods: {
clickA: function(){
alert(this.$refs.a.name)
},
clickB: function(){
alert(this.$refs.b.name)
}
},
components: {
'son-a': {
template: '<div>这是子组件:{{ msg }}</div>',
data: function () {
return {
msg: this.$parent.msg,
name: 'son-a'
}
}
},
'son-b': {
template: '<div><div>',
data: function () {
return {
name: 'son-b'
}
}
}
}
})
</script>
四. 插槽slot标签
1. 单个插槽
用于混合父组件的内容与子组件的模板
在子组件中加入<slot></slot>标签,当父组件中没有传入内容时,默认显示slot标签中的内容,反之,则将传入内容替换掉原来slot标签中的内容
<div id="app">
<my-component>
<p>{{ msg }}</p>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('my-component', {
template: `<div>
<slot>
如果父元素没传内容进来,就默认显示我吧!
</slot>
</div>`
})
var app = new Vue({
el: '#app',
data: {msg:'父元素的内容'}
})
</script>
2. 具名插槽
把父组件要传入的标签命名slot='名称',在子组件的slot标签中添加name属性
<div id="app">
<my-component>
<div slot='header'>标题</div>
<div slot='container'>正文</div>
<div slot='footer'>底部</div>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('my-component', {
template: `<div>
<slot name='header'>
如果父元素没传内容进来,就默认显示我吧!
</slot>
</div>`
})
var app = new Vue({
el: '#app',
data: {msg:'父元素的内容'}
})
</script>
3. 作用域插槽
从子组件中获取数据:在父组件中添加<template></template>标签,slot属性的值与子元素<slot>标签的name属性一样,用slot-scope属性获取传来的数据(除了name)
<div id="app">
<my-component>
<!-- 这里的prop是变量名,随便取一个名字都可以
slot的值要跟子组件的name相同
template标签不会被渲染
template标签用其他例如<p>、<span>等都可以 -->
<template slot-scope='prop' slot='abc'>
<!-- 可以获取除了name以外传来的内容 -->
{{ prop.text }}
</template>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('my-component', {
template: `<div>
<slot name='abc' text='子组件中传来的内容'>
如果父元素没传内容进来,就默认显示我吧!
</slot>
</div>`
})
var app = new Vue({
el: '#app',
data: {msg:'父元素的内容'}
})
</script>
4. 访问slot
通过this.$slots.name访问
Vue.component('my-component2', {
template: `<div>
<slot name='header'>
如果父元素没传内容进来,就默认显示我吧!
</slot>
<slot name = 'footer'></slot>
</div>`,
mounted:function(){
var header = this.$slots.header
var footer = this.$slots.footer
console.log(header[0].elm.innerText)
console.log(footer[0].elm.innerText)
}
})
五. 动态组件
VUE给我们提供 了一个元素叫component
作用是: 用来动态的挂载不同的组件
实现:使用is特性来进行实现的
<div id="app">
<!-- 绑定is属性 -->
<component :is='thisView'></component>
<button @click="handleView('A')">页面一</button>
<button @click="handleView('B')">页面二</button>
<button @click="handleView('C')">页面三</button>
<button @click="handleView('D')">页面四</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data: {
thisView: 'compA'
},
methods:{
'handleView':function(value){
this.thisView = 'comp' + value
}
},
components:{
'compA':{template:'<div>页面一</div>'},
'compB':{template:'<div>页面二</div>'},
'compC':{template:'<div>页面三</div>'},
'compD':{template:'<div>页面四</div>'}
}
})
</script>
六. 自定义指令
自定义指令的基本用法
和组件类似分全局注册和局部注册,区别就是把component换成了derective
-
钩子函数
指令定义函数提供了几个钩子函数(可选):
- bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时 执行一次的初始化动作。
- inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。 update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的 绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
- componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。 unbind: 只调用一次, 指令与元素解绑时调用。
-
钩子函数的参数有:
- el: 指令所绑定的元素,可以用来直接操作 DOM 。
- binding: 一个对象,包含以下属性:
- name: 指令名,不包括 v 前缀。
- value: 指令的绑定值, 例如: vmydirective=”1 + 1”, value 的值是 2。
- oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
- expression: 绑定值的字符串形式。 例如 vmydirective=”1 + 1” , expression 的值是 “1 + 1”。
- arg: 传给指令的参数。例如 vmydirective:foo, arg 的值是 “foo”。
- modifiers: 一个包含修饰符的对象。 例如: vmydirective.foo.bar, 修饰符对象,,,modifiers 的值是 { foo: true, bar: true }。
- vnode: Vue 编译生成的虚拟节点。
- oldVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。 自定义的指令
七、render函数
1. 基本用法
在自定义组件时,template属性内容有时会很长,而且,在切换组件内的内容时,不显示的内容可能也会渲染一遍再隐藏,而在组件中用render函数可以解决这个问题
render函数的参数必须是createElement,这是在源码中已经定义好的函数
render函数要记得把createElement函数执行结果返回出去
<div id="app">
<comp :thisview='thisView'>
<slot slot='red'>red</slot>
<slot slot='blue'>blue</slot>
</comp>
<button @click='clickRed'>red</button>
<button @click='clickBlue'>blue</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('comp', {
props: ['thisview'],
//这里的参数必须是createElement,是源码中已经定义好的函数
render: function (createElement) {
return createElement('div', this.$slots[this.thisview])
},
data: function () {
return {
view: this.thisview
}
}
})
var app = new Vue({
el: '#app',
data: { thisView: 'red' },
methods: {
clickRed: function () {
this.thisView = 'red'
},
clickBlue: function () {
this.thisView = 'blue'
}
}
})
</script>
2. createElement函数的参数
render函数返回createElement函数的执行结果
-
第一个参数 :createElement函数的第一个参数必选,可以是String、Object、Function
-
String:html标签,比如'div'、'h1'等等
Vue.component('child',{ render:function(createElement){ return createElement('div') } })
-
-
Object:含有数据选项的对象,比如:
Vue.component('child',{ render:function(createElement){ return createElement({ template: '<div>文字内容</div>' }) } })
-
Function:返回含有数据选项的对象,比如:
Vue.component('child',{ render:function(createElement){ var domFn = function(){ return { template: '<div>文字内容</div>' } } return createElement(domFn()) } })
-
第二个参数:数据对象(可选)——只能是Object
下面是一些常见的选项:style、class、attrs、domProps等
Vue.component('child',{ render:function(createElement){ return createElement({ template: '<div>文字内容</div>' },{ 'class': { //表示类名class,true为有该类名,false则相反 //class在js中是关键字,最好用引号包起来,不加也没事 foo: true, baz: false }, style: { color: 'red', //css中的横杆命名在这里都要写成驼峰命名 fontSize: '20px' }, attrs: { //attributes,正常的HTML属性,大部分可以写进来 id: 'red', src: '../XXX.jpg' }, domProps: { //用来写原生的DOM属性 innerHTML: '<span style="color:red;">文字内容</span>' } }) } })
-
第三个参数:代表子节点,可选——可以是String 或 Array(Array常用)
因为第二个参数可选且必须为Object,所以,如果第二个参数为String或Array,那么意味着第二个参数为空,这个String或Array是第三个参数,子节点
其实第三个参数存的就是VNODE虚拟节点
Vue.component('child',{ render: function(createElement){ return createElement({ template: '<div>内容</div>' },{ class:{ red: true } },[ //这里的内容时字符串,不是对象,所以也是子节点(第三个参数) createElement('span','内容'), createElement('span','内容') ]) } })
3. this.$slots在render函数中的使用
插槽的用法
第三个 参数存的就是VNODE
createElement(‘header’,header), 返回的就是VNODE
var header = this.$slots.header; //这返回的内容就是含有VNODE的数组
<div id="app">
<child>
<span slot='header'>我是标题</span>
<span slot='main'>我是正文</span>
<span slot='main'>我是正文</span>
<span slot='footer'>我是结尾</span>
</child>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('child', {
render: function (createElement) {
var header = this.$slots.header
var main = this.$slots.main
var footer = this.$slots.footer
return createElement('div', {
'class': {
red: true
}
}, [
createElement('header', header),
createElement('main', main),
createElement('footer', footer)
])
}
})
var app = new Vue({
el: '#app',
data: {}
})
4. 在 render中使用props传递数据
5. 在render函数中使用v-model
<div id="app">
<my-component :inputvalue='inputvalue' @change='changevalue'></my-component><br>
<!-- 这里的v-model是语法糖,绑定input事件,当触发input事件时,把传来的值付给inputvalue -->
<my-component :inputvalue='inputvalue' v-model='inputvalue'></my-component><br>
{{ inputvalue }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data: {
inputvalue: '111'
},
methods: {
changevalue: function (value) {
this.inputvalue = value
}
},
components: {
'my-component': {
props: ['inputvalue'],
render: function (createElement) {
return createElement('input', {
attrs: {
value: this.inputvalue
},
on: {
input: (event) => {
this.$emit('change', event.target.value)
this.$emit('input', event.target.value)
}
}
})
}
}
}
})
</script>
6. 作用域插槽
向组件的插槽中传递数据
$scopedSlots.default
<div id="app">
<my-component>
<template scope='abc'>
{{ abc.text }}<br>
{{ abc.name }}
</template>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data: {},
components: {
'my-component': {
render: function (createElement) {
return createElement('div', this.$scopedSlots.default({
text: '我是子组件传来的数据',
name: '陈秋钿'
}))
}
}
}
})
</script>
7. 函数化组件
functional:true //表示当前Vue实例无状态、无实例
无实例:组件内部没有this,可以通过context上下文来解决,render函数的第一个参数是createElement,第二个参数是context,这里this是window
context.parent
context.props
context.props.text ---- this.text
context.children ----- this.$slots.default
八. vue-cli脚手架
1. 安装步骤
首先电脑上要安装最新版的nodeJS.官网下载,安装完之后安装淘宝npm镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
-
安装五部走:
-
全局安装vuecli
npm install -g vue-cli
-
进入目录–初始化项目
vue init webpack my-project
-
进入项目
cd my-project
-
安装依赖
npm install
-
启动项目
npm run dev
-
-
部署项目:
npm run build
2. 目录结构
├── build // 项目构建(webpack)相关代码 记忆:(够贱) 9个
│ ├── build.js // 生产环境构建代码
│ ├── checkversions.js // 检查node&npm等版本
│ ├── devclient.js // 热加载相关
│ ├── devserver.js // 构建本地服务器
│ ├── utils.js // 构建配置公用工具
│ ├── vueloader.conf.js // vue加载器
│ ├── webpack.base.conf.js // webpack基础环境配置 //entry程序的入口
│ ├── webpack.dev.conf.js // webpack开发环境配置
│ └── webpack.prod.conf.js // webpack生产环境配置
二、
├── config// 项目开发环境配置相关代码 记忆: (环配) 3个
│ ├── dev.env.js // 开发环境变量(看词明意)
│ ├── index.js //项目一些配置变量
│ └── prod.env.js // 生产环境变量
三、
├──node_modules// 项目依赖的模块 记忆: (依赖) *个
四、
├── src// 源码目录5
1
│ ├── assets// 资源目录
│ │ └── logo.png
2
│ ├── components// vue公共组件
│ │ └── Hello.vue
3
│ ├──router// 前端路由
│ │ └── index.js// 路由配置文件
4
│ ├── App.vue// 页面入口文件(根组件)
5
│ └── main.js// 程序入口文件(入口js文件)
五、
└── static// 静态文件,比如一些图片,json数据等
│ ├── .gitkeep
剩余、
├── .babelrc// ES6语法编译配置
├── .editorconfig// 定义代码格式
├── .gitignore// git上传需要忽略的文件格式
├── index.html// 入口页面
├── package.json// 项目基本信息
├── README.md// 项目说明
3. 其他
以 .vue 结尾的是组件文件,组件文件中的样式只对组件中的标签有用
九. 前端路由和vuex状态管理
访问不同的路由,加载不同的组件(输入不同的网址,显示不同的内容)
watch: {
// 如果路由有变化,会再次执行该方法
$route: "getUserData"
}
1. vue-router路由基本加载
-
安装
npm install --save vue-router
- 引用
import router from 'vue-router' Vue.use(router)
-
配置路由文件,并在vue实例中注入
var rt = new router({ routes:[{ //这里是routes,不是routers啊 path:'/',//指定要跳转的路径 component:HelloWorld//指定要跳转的组件 }] }) new Vue({ el: '#app', router: rt, components: { App }, template: '' })
-
确定视图加载的位置
<router-view></router-view>
2. 路由的跳转
用router-link
<router-link to="/"></router-link>
<template>
<ul>
<li>
<router-link to="/helloworld">HELLO WORLD</router-link>
</li>
<li>
<router-link to="/helloearth">HELLO EARTH</router-link>
</li>
</ul>
</template>
3. 通过路由传递参数
- 在路由中加入name属性
- 在path后面加 "/ : 要传递的参数 "
- 在router-link标签中绑定to,name 和 params结合使用,在组件中用 $route.params.XXX 获取传来的参数
<!-- list.vue -->
<template>
<ul>
<li>
<router-link :to="{name: 'helloworld',params:{worldmsg: '你好世界'}}">
HELLO WORLD
</router-link>
</li>
<li>
<router-link :to="{name:'helloearth',params:{earthmsg:'你好地球'}}">
HELLO EARTH
</router-link>
</li>
</ul>
</template>
<!-- HelloEarth.vue -->
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<h3>{{ $route.params.earthmsg }}</h3>
</div>
</template>
<script>
export default {
name: 'HelloEarth',
data () {
return {
msg: 'HELLO EARTH'
}
}
}
</script>
// index.js(router)
export default new router({
routes: [{
name: 'helloworld',
path: '/helloworld/:worldmsg',
component: HelloWorld
},{
name: 'helloearth',
path: '/helloearth/:earthmsg',
component: HelloEarth
}]
})
4. Axios —— get请求
this.$http.get( 'url ', {params:{}})
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:
- 从浏览器中创建 XMLHttpRequest
- 从 node.js 发出 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防止 CSRF/XSRF
-
使用方法
-
安装
npm install axios
-
引入加载
import axios from 'axios'
-
将axios挂载到全局Vue上(不用每个文件都引入加载)
Vue.prototype.$http = axios
这里的http.get()函数就能发送请求,(这里this是指当前Vue实例)
-
发出get请求
axios基于promise,有.then()、.catch()
在请求链接上加参数的两种方法:
直接在链接后面加 ?page=1&limit=10
或者,get函数加第二个参数 {params:{ page:1;limit:10}}
<template> <div> <button @click='getData'>点击请求数据</button> <ul> <li v-for="item in items">{{item.title}}</li> </ul> </div> </template> <script> export default { name: "HelloWorld", data() { return { msg: "Welcome to Your Vue.js App", items: [] }; }, methods: { getData() { // this.$http.get('https://cnodejs.org/api/v1/topics?page=1&limit=10') this.$http .get("https://cnodejs.org/api/v1/topics", { params: { page: 1, limit: 10 } }) .then(res => { this.items = res.data.data; console.log(res.data.data); }) .catch(function(err) { console.log(err); }); } } }; </script>
-
5. Axios —— post请求
与get相似,把get换成post
-
POST传递数据有两种格式:
formdata格式: ?page=1&limit=48
xwwwformurlencoded格式: { page: 1,limit: 10 }
-
在axios中,post请求接收的参数必须是formdata格式,可以使用qs插件把我们写的内容转换为formdata格式
qs插件—qs.stringify
npm install qs
import qs from'qs'
postData() {
this.$http.post(url, qs.stringify({
params: {
page: 1,
limit: 10
}
}))
.then(res => {
this.items = res.data.data;
console.log(res.data.data);
})
.catch(function(err) {
console.log(err);
});
}
6.vuex的store用法
子组件和父组件之间的通信可以通过props以及$emit来完成,非父组件之间的通信需要通过他们之间的共同父组件来完成,当文件较多时,就会很乱很麻烦,所以就用到了Vuex的store
简而言之,vuex可以用来管理状态,共享数据,在各个组件之间管理外部状态
应用场景:多个页面间共享的登录状态
-
安装vuex,引入并通过use方法使用它
npm i vuex
import Vuex from 'vuex'
Vue.use(Vuex)
-
创建状态仓库
//这里的Store和state是不能改的! var store = new Vuex.Store({ //state 状态 state: { num: 100 } }) //在入口文件中引入store,跟引入router一样 new Vue({ el: '#app', router, store, //就是这一句 components: { App }, template: '<App/>' })
-
在任意组件中,都可以通过 this.$store.state.XXX 直接拿到共享的数据
computed:{ getNum:function(){ return this.$store.state.num } }
7. vuex的相关操作及核心用法
vuex状态管理的流程
view———>actions———–>mutations—–>state————>view
方法1:在mutations选项中定义状态改变事件,在组件中通过this.$store.commit('事件名')触发转台的改变
-
方法2:actions,用来操作mutations的,可有可无,但是actions可以进行异步操作而mutations不能,
通过this.$store.dispatch('事件名')
注意:actions提交的是mutation,而不是直接变更状态
actions可以包含异步操作,但是mutation只能包含同步操作
-
方法三:getters,我觉得这个跟计算属性有点像
var store = new Vuex.Store({ state: { num: 100 }, mutations:{ addNum(state){ state.num ++ }, reduceNum(state){ state.num -- } }, actions:{ //传入的参数为上下文 ruduce(context){ context.commit('reduceNum') } }, getters:{ getCount(state){ return state.num > 0 ? state.num : 0 } } }) //在组件中 this.$store.commit('addNum') this.$store.dispatch('ruduce') this.$store.getters('getCount')
十. 过渡
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
new Vue({
el: '#demo',
data: {
show: true
}
})
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
在进入/离开的过渡中,会有 6 个 class 切换。
-
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。 -
v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。 -
v-enter-to
: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时v-enter
被移除),在过渡/动画完成之后移除。 -
v-leave
: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。 -
v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。 -
v-leave-to
: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时v-leave
被删除),在过渡/动画完成之后移除。