文章目录
第一章 Vue核心知识讲解
初识VUE,走进VUE的世界
历史介绍
- angular 09年,年份较早,一开始大家是拒绝 star:59.3k
- react 2013年, 用户体验好,直接拉到一堆粉丝 star:119k
- vue 2014年, 用户体验好 star:124k
Vue等框架与jQuery的区别
- jQuery是基于操作dom的库
- Vue框架是以数据驱动和组件化开发为核心
引包、留坑、实例化 、插值表达式{{}}
开展vue,用vue做出自己的第一个网页的步骤
下载vue包
npm init --yes
npm install vue@2.5.21
引包
在node_modules\vue文件夹中取出来vue.js
创建一个页面引入刚下载的包
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引包 -->
<script type="text/javascript" src="vue.js"></script>
</head>
<body>
</body>
</html>
留坑
即留一个vue模板插入的地方或者是vue代码对其生效的地方
实例化—即启动Vue
启动: new Vue({el:目的地,template:模板内容});实例化传入的是一个对象options
options
- 目的地 el 对应上面留坑的坑位,可通过id名,类名,标签名来查找。方式和jq一样
- 内容 template
- 数据 data 值为函数形式也可是对象,但是都是用函数,因为用的函数最后也是return一个对象
<script type="text/javascript">
// 实例化启动vue
new Vue({
el:'#app',//目的的,可以识别类名、id名和标签名,如果做到极致优化可以直接用document.getElementById获取
template:`
<div>
<div>我这里是模板内容</div>
<div>111</div>
</div>
})
</script>
现在打开网页的内容,为
插值表达式{{ }}
插值表达式内填入data里面的变量即可在页面取到变量值{{data}},用到的变量都要在data里面声明,
data:function(){
return {
msg:'Hello Vue!'
}
}
整个测试代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 留坑 -->
<div id="app"></div>
<!-- 引包 -->
</body>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
// 实例化启动vue
new Vue({
el:'#app',//目的的,可以识别类名、id名和标签名,如果做到极致优化可以直接用document.getElementById获取
template:`
<div> // 根节点只能有一个
<div>我这里是模板内容</div>
<div>111</div>
</div>`,
data:function(){
return {
msg:'Hello Vue!'
}
}
})
</script>
</html>
熟悉及使用常用指令
什么是指令
在vue中提供一些对于页面+数据的更为方便的操作,这些操作就叫做指令。譬如在HTML页面中这样使用
<div v-xxx=''></div>
在vue中v-xxx就是vue的指令
指令就是以数据去驱动DOM行为的,简化DOM操作
常用的指令
- v-text 不可解析html标签
- v-html 可解析html标签
- v-if 做元素的插入(append)和移除(remove)操作
- v-else-if
- v-else
- v-show display:none 和display:block的切换
- v-for
- 数组 item,index
- 对象 value,key ,index
示例代码
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
template:`
<div>
<!--测试v-text-->
<div v-text='mytext'></div>
</hr>
<!--测试v-html-->
<div v-html='myhtml'></div>
<!--测试v-if v-else-if v-else-->
<button v-if='num==1'>测试v-if</button>
<button v-else-if='num==2'>测试v-else-if</button>
<button v-else>测试v-else</button>
<!--测试v-show-->
<div v-show='checkshow'>我是V-SHOW</div>
<!--循环数组-->
<ul>
<li v-for='(item,index) in arrayfor'>
{{ item }}-{{index}}
</li>
</ul>
<ul>
<!--循环对象-->
<li v-for='(oj,key) in ojfor'>
{{key}}:{{oj}}
</li>
</ul>
</div>
`,
data:function(){
return {
mytext:'<h1>我这里是v-text</h1>',
myhtml:'<h1>我这里是v-html</h1>',
checkvif:true,
num:6,
checkshow:true,
arrayfor:['篮球','足球','乒乓球'],
ojfor:{play:'篮球',people:'ming',age:'19'}
}
}
})
</script>
</body>
</html>
阐述vue单双向数据流及事件绑定
单向数据绑定
vue单向数据流绑定属性值 v-bind: (属性) 简写 :(属性),例子
<input v-bind:value="name" v-bind:class="name">
- 单向数据绑定 内存改变影响页面改变(在html页面中定义后,改变值不改变页面中的定义)
- v-bind就是对属性的简单赋值,当内存中值改变,还是会触发重新渲染
双向数据绑定
vue双向数据流 v-model 只作用于有value属性的元素,例子
<input v-model="name" v-bind:class="name">
- 双向数据绑定 页面对于input的value改变,能影响内存中name变量
- 内存js改变name的值,会影响页面重新渲染最新值
事件绑定
事件绑定v-on:事件名=“表达式||函数名” 简写 @事件名=“表达式||函数名”
- 事件名可以是原生也可以是自定义的
事件绑定如果是卸载methods中的函数,则需要带上this参数,如果直接在函数中写上则不需要带this
<button v-on:click="name='点击我改变name变量'">点击我改变name变量</button>
<button v-on:click="change">点击我改变name变量2</button>
示例代码如下
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
console.log(this)
new Vue({
el:"#app",
template:`
<div>
单向数据绑定
<input type='text' v-bind:value="name" :class="name"><br>
双向数据绑定
<input type='text' v-model="name"></br>
{{ name }}
<button v-on:click="name='点击我改变name变量'">点击我改变name变量</button>
</br>
{{ name }}
<button v-on:click="change">点击我改变name变量2</button>
</div>
`,
data:function(){
return {
name:'hello'
}
},
methods:{
change:function(){
console.log(this)
this.name='我改变了,是在方法属性里面定义的方法'
},
}
})
</script>
</body>
</html>
总结:
v-model双向数据绑定
- vue页面改变影响内存(js)
- 内存(js)改变影响vue页面
v-bind 单向数据绑定只是内存(js)改变影响vue页面
过滤器
过滤器就是可以对我们的数据进行添油加醋然后再显示(需要先声明再使用)
过滤器有全局过滤器和组件内的过滤器
- 全局过滤器Vue.filter(‘过滤器名’,过滤方式fn );
- 组件内的过滤器 filters:{ ‘过滤器名’,过滤方式fn }
- {{ msg | 过滤器名}}
组件内过滤器的方式的示例代码
<!DOCTYPE html>
<html>
<head>
<title>过滤器</title>
</head>
<body>
<div id="app">
我输入的:<input type="text" name="" v-model='instring'></br>
我输出的:{{ instring }}</br>
{{ instring | reversal('翻转输出:')}}
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data(){
return {
instring:''
}
},
// 第一个参数固定为传入的左边变量
filters:{
reversal(val,arg2){
// 字符串转数组 翻转 数组转字符串
return arg2+val.split('').reverse().join('')
}
}
})
</script>
</body>
</html>
全局过滤器的示例代码
<!DOCTYPE html>
<html>
<head>
<title>过滤器</title>
</head>
<body>
<div id="app">
我输入的:<input type="text" name="" v-model='instring'></br>
我输出的:{{ instring }}</br>
{{ instring | reversal('翻转输出:')}}
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
Vue.filter('reversal', function(val, arg2){
return arg2+val.split('').reverse().join('')
})
new Vue({
el:'#app',
data(){
return {
instring:''
}
},
})
</script>
</body>
</html>
最终都是在过滤方式fn里面return产出最终你需要的数据
vue中的this是vue封装好给我们使用的,跟平常方法里面的this是不同的
数据监听watch计算属性computed
watch监听单个,computed监听多个,思考业务场景:
- 类似淘宝,当我输入某个人名字时,我想触发某个效果
- 利用vue做一个简单的计算器
示例代码
<div id="app">
<div>watch监听数据</div>
<input type="text" name="" v-model='msg'>
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data(){
return {
msg:'',
}
},
watch:{
msg(newval, oldval) {
if(newval=='love'){
alert(newval)
}
}
}
})
</script>
当watch监听的是复杂数据类型的时候需要做深度监听(写法如下)
<div id="app">
<div>watch监听数据</div>
<input type="text" name="" v-model='msg.text'>
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data(){
return {
msg:{text:''},
}
},
watch:{
msg:{
handler(newval,oldval){
if(newval.text=='love'){
alert(newval.text)
}
},
deep:true // 开启深度监听
}
}
})
</script>
computed 监视对象,写在了函数内部,凡是函数内部有this.相关属性,改变都会触发当前函数,示例代码如下
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="app">
<div>computed计算属性</div>
(<input type="text" name="" v-model='n1'>+
<input type="text" name="" v-model='n2'>)*
<input type="text" name="" v-model='n3'>={{result}}
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data(){
return {
msg:{text:''},
n1:'',
n2:'',
n3:'1'
}
},
computed:{
result(){
return (Number(this.n1)+Number(this.n2))*Number(this.n3)
}
},
})
</script>
</body>
</html>
组件化开发知识介绍
组件化开发
组件化开发能让我们的项目更加灵活
创建组件的两种方式
var Header = { template:'模板' , data是一个函数,methods:功能,components:子组件们 }//局
部声明
Vue.component('组件名',组件对象);//全局注册 等于注册加声明了
组件类型
- 通用组件(例如表单、弹窗、布局类等)
- 业务组件(抽奖、机器分类)
- 页面组件(单页面开发程序的每个页面的都是一个组件、只完成功能、不复用)
组件开发三步曲:声明、注册、使用
示例代码如下
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
// 这个是语法糖
var MyHeader = {
template:`
<div>我是头部</div>
`,
}
// 一般形式是这样的
var MyBody = Vue.extend({
template:`
<div>我是身体</div>
`,
})
Vue.component('MyFooter', {
template:`
<div>我是尾部</div>
`
})
new Vue({
el:'#app',
// 注册组件
components: {
MyHeader,
MyBody
},
template:`
<div>
<My-Header></My-Header> 也可以用My-Header的名字调用
<MyBody></MyBody>
<my-footer></my-footer>
</div>
`,
data(){
return{}
},
})
</script>
</body>
</html>
slot插槽和ref、$parent
slot插槽
- slot就是子组件里给DOM留下的坑位
- <子组件>DOM</子组件>
- slot是动态的DOM
示例代码
<!DOCTYPE html>
<html>
<head>
<title>组件化开发</title>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var MyParent={
template:`
<div>
我是父组件
<h2>
<slot name='hello'></slot>
</h2>
</div>
`,
}
new Vue({
el:'#app',
components:{
MyParent
},
template:`
<div>
<MyParent>
<div>你是看不到这个输出的,因为没有对应的slot name</div>
<div slot='hello'>如果指定了name,就只显示对应的组件</div>
</MyParent>
</div>
`,
data(){
return{}
},
})
</script>
</body>
</html>
ref获取子组件实例
- 识别:在子组件或元素上使用属性ref=“xxxx”
- 获取:this.$refs.xxxx 获取元素
- $el 是拿其DOM
p a r e n t 获 取 父 组 件 实 例 ( 可 在 子 组 件 直 接 使 用 t h i s . parent获取父组件实例(可在子组件直接使用this. parent获取父组件实例(可在子组件直接使用this.parent即可)
可以用作后面的父子组件的通信
示例代码
<!DOCTYPE html>
<html>
<head>
<title>组件化开发</title>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var Child={
template:`
<div>我是子组件</div>
`,
data(){
return {
msg:'hello'
}
},
created(){
console.log("通过this.$parent可以找到父组件,也能调用父组件的方法", this.$parent)
}
}
var Parent={
template:`
<div>
我是父组件
<slot name='hello'></slot>
<child ref='childs'></child>
</div>
`,
components:{
Child
},
data(){
return {
parents:'我是父组件'
}
},
mounted(){
console.log("通过this.$refs.childs可以找到子组件,也能调用子组件的方法", this.$refs.childs)
}
}
new Vue({
el:'#app',
components:{
Parent
},
template:`
<div>
<parent>
<div>我是插槽内容</div>
<div slot='hello'>我是插槽内容2</div>
</parent>
</div>
`,
data(){
return{}
},
})
</script>
</body>
</html>
父子组件的通信
父传子
- 父用子的时候通过属性传递
- 子要声明props:[‘属性名’] 来接收
- 收到就是自己的了,随便你用
- 在template中直接用
- 在js中 this.属性名用
示例代码如下
<!DOCTYPE html>
<html>
<head>
<title>组件化开发</title>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var Child={
template:`
<div>
我是子组件
<h2>{{sendchild}}</h2>
</div>
`,
props:['sendchild'], // 通過props来传递值
}
var Parent={
template:`
<div>
我是父组件
<child sendchild="zengraoli"></child>
</div>
`,
components:{
Child
},
}
new Vue({
el:'#app',
components:{
Parent
},
template:`
<div>
<parent>
<div>我是插槽内容</div>
<div slot='hello'>我是插槽内容2</div>
</parent>
</div>
`,
data(){
return{}
},
})
</script>
</body>
</html>
子传父
- 子组件里通过$emit(‘自定义事件名’,变量1,变量2)触发
- 父组件@自定义事件名=‘事件名’监听
示例代码如下
<!DOCTYPE html>
<html>
<head>
<title>组件化开发</title>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var Child={
template:`
<div>
我是子组件
<h2>{{sendchild}}</h2>
<button @click='sendparent'>我要反馈东西给父组件,点击后$emit触发父组件的baba函数</button>
</div>
`,
props:['sendchild'], // 通過props来传递值
methods:{
sendparent(){
this.$emit('baba','这是儿子组件给你的')
}
}
}
var Parent={
template:`
<div>
我是父组件
<child sendchild='父亲给你的' @baba='reserve'></child>
子组件传过来的数据:{{childMsg}}
</div>
`,
components:{
Child
},
data(){
return {
childMsg:''
}
},
methods:{
reserve(val) {
this.childMsg = val
}
}
}
new Vue({
el:'#app',
components:{
Parent
},
template:`
<div>
<parent>
</parent>
</div>
`,
data(){
return{}
},
})
</script>
</body>
</html>
非父子组件之间的通信
创建一个空实例(bus中央事件总线也可以叫中间组件)
利用$emit $on的触发和监听事件实现非父子组件的通信
Vue.prototype.$bus=new Vue()//在vue上面挂载一个$bus作为中央处理组件
this.$bus.$emit('自定义事件名','传递的数据')//触发自定义事件传递数据
this.$bus.$on('自定义事件名',fn)//监听自定义事件获取数据
解决的方案还有vuex、provide/inject是解决同根往下派发、本地存储也可以进行非父子组件之间的通信
简单的使用就使用中间过渡的形式,示例代码如下
<!DOCTYPE html>
<html>
<head>
<title>非父子组件的通信</title>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
Vue.prototype.$bus=new Vue()
var MyHeader={
template:`
<div>
我是头部
{{ headermsg }}
</div>
`,
data(){
return {
headermsg:'我是头部的信息'
}
},
created() {
// 在created中新建一个监听数据的事件
var self = this
self.$bus.$on('sending', function(val){
self.headermsg=val
})
// 另外一个使用---箭头函数的定义域需要区分一下
// this.$bus.$on('sending',val=>{
// this.headermsg=val
// })
}
}
var MyBody={
template:`
<div>我是身体</div>
`,
}
var MyFooter={
template:`
<div>我是底部<button @click="sendHeader">我要跟头部通信</button></div>
`,
methods:{
sendHeader(){
this.$bus.$emit('sending', '我是底部传过来的数据')
}
}
}
new Vue({
el:'#app',
components:{
MyHeader,
MyBody,
MyFooter
},
template:`
<div>
<my-header></my-header><hr>
<my-body></my-body><hr>
<my-footer></my-footer>
</div>
`,
data(){
return {}
},
})
</script>
</body>
</html>
vue的生命周期
需要频繁的创建和销毁组件
- 比如页面中部分内容显示与隐藏,但是用的是v-if
组件缓存
- 内置组件中
- 被其包裹的组件,在v-if=false的时候,不会销毁,而是停用
- v-if=“true” 不会创建,而是激活
- 避免频繁创建组件对象的性能损耗
- 组件的激活和停用
- activated 和 deactivated
成对比较
- created 和 beforeCreate
- A 可以操作数据 B 数据没有初始化
- mounted 和 beforeMount
- A 可以操作DOM B 还未生成DOM
- updated 和 beforeUpdate
- A 可以获取最终数据 B 可以二次修改
destroyed 和 beforeDestroy
性能调优:频繁销毁创建的组件使用内置组件包裹
参考官网:https://cn.vuejs.org/v2/guide/instance.html#生命周期图示
演示的小例子代码如下,app.js内容(仅仅是引入实现代码main.js)
<!DOCTYPE html>
<html>
<head>
<title>vue的生命周期</title>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="main.js">
</script>
</body>
</html>
main.js代码
var Test={
template:`
<div>我是Test组件{{ msg }}
<button @click="msg+='1'">msg+1</button>
</div>
`,
data(){
return{
msg:'HELLO VUE'
}
},
//组件创建前
beforeCreate(){
console.log('组件创建前')
console.log(this.msg)
},
//组件创建后
created(){
console.log('组件创建后')
console.log(this.msg)
},
//Dom挂载前
// beforeMount(){
// console.log('Dom挂载前')
// console.log(document.body.innerHTML)
// },
// //Dom挂载后
// mounted(){
// console.log('Dom挂载后')
// console.log(document.body.innerHTML)
// }
//基于数据更新前
beforeUpdate(){
console.log('数据更新前')
console.log(document.body.innerHTML)
},
//基于数据更新后
updated(){
console.log('数据更新后')
console.log(document.body.innerHTML)
},
//销毁前
beforeDestroy(){
console.log('销毁前')
},
//销毁后
destroyed(){
console.log('销毁后')
},
//组件停用
deactivated(){
console.log('组件停用')
},
//组件激活
activated (){
console.log('组件激活')
}
}
new Vue({
el:'#app',
components:{
Test
},
template:`
<div>
<keep-alive><test v-if='testshow'></test></keep-alive></br>
<button @click='clickbut'>销毁组件</button>
</div>
`,
data(){
return {
testshow:true
}
},
methods:{
clickbut(){
this.testshow=!this.testshow
}
}
})