一、VUE
- vue是一个渐进式的框架(vue作为应用的一部分嵌入其中,一点点的实行替换)
- vue的功能
(1)解耦视图和数据
(2)可复用组件
(3)前端路由技术
(4)状态管理 - vuejs的安装方式
1.CDN安装
2.链接下载引入
3.NPM安装
- 每个vue页面只能有一个根标签
1.1、指令
{{}}
写在标签中(Mustache语法),动态的展示数据,标签中的内容可以是属性,也可以时方法v-once
后面不需要加任何表达式,该指令表示组件和元素只会渲染一次,用于固定数据,消除响应式v-pre
后面不需要加任何表达式,该指令可以原封不动的展示标签内的数据<h4 v-pre>{{message}}</h4>
,会直接输出{{message}}
v-html
当渲染的数据有标签元素时,用于解析HTML代码
<div id="app">
<h4 v-html='url'></h4>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
url: '<a href="http://www.baidu.com">百度一下</a>'
}
})
</script>
</body>
v-text
用于将数据显示在界面中,和双大括号功能一样(但是不够灵活)
<body>
<div id="app">
1. v-text会覆盖原来的数据
<h4 v-text="message">,小明同学</h4>
2. {{}}会拼接原来的数据
<h4>{{message}},小明同学</h4>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
message: '小明同学',
}
</script>
</body>
v-cloak
:后面不需要加任何表达式,用于当数据有延时效果时- 一般减一使用计算属性,不建议使用v-if和v-if-else
1.1.1、v-bind动态绑定
- v-bind:动态绑定属性
<img v-bind:src="url" alt="">
;v-bind
的语法糖是:
<div id="app">
<!-- 需要从数据库中拿到数据,需要使用v-bind实现动态绑定 -->
<img v-bind:src="url" alt="">
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
url: 'https://cn.vuejs.org/images/components.png',
}
})
</script>
v-bind
绑定class属性,实现动态绑定class样式(排他思想):如下实现点击按钮字体变色
(1)<h4 :class="{active:isActive}">{{message}}</h4>
,class
用{}
引起来的是对象,里面存在的是键值对,可以有多个
(2)普通的class和动态绑定的class是可以共存的<h4 :class="{active:isActive}" class="title">{{message}}</h4>
<body>
<div id="app" v-cloak>
<h4 :class="{active:isActive}" class="title">{{message}}</h4>
<button v-on:click='clickbtn'>按钮</button>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
message: '小明同学',
isActive: true,
},
methods: {
clickbtn: function() {
this.isActive = !this.isActive;
}
}
})
</script>
</body>
- v-bind动态绑定style样式(样式可以实现动态改变,直接从后台拿值,不需要手动修改),将样式封装成方法看起来更简洁
<body>
<div id="app" v-cloak>
<!-- 如下帮的那个样式的两种方式 1.直接绑定加引号 2.不加引号在data中 -->
<!-- 将样式封装成方法 -->
<h4 :style="getStyle()">{{message}}</h4>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
message: '小明同学',
conSize: '50px',
},
methods: {
getStyle: function() {
return {
color: 'red',
fontSize: this.conSize
};
}
}
})
</script>
</body>
1.1.2、计算属性
- 计算属性computed,(是对vue对象中的属性进行操作),对数据进行一些转化后再显示
<body>
<div id="app" v-cloak>
<h4>{{message1}}{{msessage2}}</h4>
<!-- 计算属性,不是函数没必要加括号,一般只调用get方法,所以干脆直接省略get -->
<h4>{{fullName}}</h4>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
message1: '小明同学',
msessage2: '和小刚同学'
},
//计算属性
computed: {
fullName: function() {
return this.message1 + this.msessage2;
}
}
})
</script>
</body>
- 计算属性的get和set方法,但是一般不给set方法设置值,只定义get方法
//计算属性
computed: {
//计算属性名
fulName: {
set: function() {
},
get: function() {
}
}
1.1.2.1、计算属性缓存
- 对数据进行拼接处理有 三种方式
(1)Mustache拼接
(2)使用方法
(3) 使用计算 属性 - 计算属性computed和函数methods都可以实现功能, 但是计算属性会进行缓存,当多次调用时,计算属性会只调用一次,而普通函数会调用多次
<body>
<div id="app" v-cloak>
<!-- 1.双大括号拼接 -->
<h4>{{message1}}{{msessage2}}</h4>
<!-- 2.计算属性computed -->
<h4>{{fullName}}</h4>
<!-- 3.定义方法 -->
<h4>{{getFullName()}}</h4>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
message1: '小明同学',
msessage2: '和小刚同学'
},
//计算属性
computed: {
fullName: function() {
console.log('fullName');
return this.message1 + this.msessage2;
}
},
//方法
methods: {
getFullName: function() {
console.log('fullName');
return this.message1 + this.msessage2;
}
}
})
</script>
</body>
1.1.3、v-on监听事件
- 使用
v-on
来监听事件,比如点击,拖拽,键盘事件等;ES6语法糖将v-on:
改为@
- 当监听事件时,函数中不需要参数那么就不需要在函数后加括号,当需要传递参数时是需要加括号的(计算属性是不需要括号的)
- 事件定义时,写函数时省略了小括号,但是方法本身是需要一个参数的,这时vue会将浏览器产生的event事件对象作为参数传递到函数中
1.1.3.1、v-on监听事件参数
- 在调用时,手动获取浏览器参数的event对象:
$event
(当事件中的参数不加引号时,会把它当成变量或方法去data中寻找)
<body>
<div id="app">
<!-- 当事件中的参数不加双引号时,会把它当成变量或方法去data中寻找 -->
<h4 @click='clickbtn("小明",$event)'>{{message}}</h4>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
message: '小明同学',
},
methods: {
clickbtn(abc, event) {
//传过来的参数event是浏览器参数
console.log(abc, event);
}
}
})
</script>
</body>
1.1.3.2、v-on修饰符
修饰符 | 描述 |
---|---|
.stop | 阻止冒泡 |
.prevent | 阻止默认事件 |
.enter | 监听键盘的事件 |
.native | 监听vue 中组件事件 |
.once | 鼠标只允许点击一次 |
1.1.4、v-show与v-if
v-show
和v-if
相似,都是决定一个元素是否被渲染,那开发中如何使用呢?- 当显示隐藏切换很频繁时,使用
v-show
;当只有一次切换时,使用v-if
v-if
当条件为false
时,不会渲染到DOM中,当v-show
为false
时,设置display
为none
1.1.5、v-model
- v-model实现双向绑定(和
{{}}
差不多)
1.1.5.1、v-model结合checkbox使用
<body>
<div id="app">
<!-- 单选框 布尔值-->
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
</label><br>
<button v-bind:disabled="!isAgree">下一步</button>
<!-- 多选框 数组 -->
<input type="checkbox" value="篮球" v-model="isEval">篮球
<input type="checkbox" value="足球" v-model="isEval">足球
<input type="checkbox" value="羽毛球" v-model="isEval">羽毛球
<!-- 可以用如下来做判断 -->
<h2>{{isEval}}</h2>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
//单选
isAgree: false,
//多选
isEval: [],
}
})
</script>
1.1.5.2、值绑定(动态,不会写死)
<body>
<div id="app">
<label v-for="item in ball1">
<input type="checkbox" :value="item" v-model="hobbies">{{item}}
</label>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
hobbies: [],
ball1: ['篮球', '足球', '羽毛球', '台球'],
}
})
</script>
1.1.5.3、v-model结合select使用
<body>
<div id="app">
<select name="" id="" v-model="ball">
<option value="足球">足球</option>
<option value="篮球" >篮球</option>
<option value="羽毛球">羽毛球</option>
</select>
<!-- 做验证 -->
<h4>{{ball}}</h4>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
ball: '篮球',
}
})
</script>
1.1.5.4、v-model修饰符的使用
修饰符 | 描述 |
---|---|
v-nodel.lazy | 实现懒加载 |
v-model.number | |
v-model.trim | 去除空格 |
- lazy修饰符可以在数据失去焦点或回车的时候才更新,不会实时绑定
1.2、属性
- el:挂载点
- data:数据
- compted:定义函数的 计算属性fullName(){}
- methods:定义函数的 getFullName(){}
- components:用来注册局部组件的
1.3、生命周期
- 生命周期 :实例的创建和销毁的一个过程
- option对象里可以传入
el
,data
,methods
,还可以传入生命周期的钩子函数(create(),mounted(),updated(),destoryed()等)
1.绿色表示是
new Vue()
时,内部做的
2.红色表示的是钩子函数:是在new Vue()
中实现的函数,如:create()
,mounted()
,updated()
,destory()
等
二、ES6补充
1.1、let和var
- let新增了块级作用域 (只要出现花括号就是块级作用域,,不论外边的值如何发生变化,都不会影响函数内的值(值是固定好的)),不存在变量提升;在之前只有函数有作用域
- 如下输出打印了5
<ul>
<li>小明</li>
<li>小红</li>
<li>皮卡</li>
<li>杰尼龟</li>
<li>闪电</li>
</ul>
<script>
var li = document.querySelectorAll('li');
//循环绑定事件
//for循环是同步任务,会立即执行
for (var i = 0; i < li.length; i++) {
li[i].index = i;
//function是异步任务,会点击后再执行
li[i].addEventListener('click', function() {
console.log(this.index);
})
}
</script>
- 加了闭包之后,可以正常输出(因为闭包是函数,函数是有自己的作用域的)
<ul>
<li>小明</li>
<li>小红</li>
<li>皮卡</li>
<li>杰尼龟</li>
<li>闪电</li>
</ul>
<script>
// 2.通过闭包获取索引号
var li = document.querySelectorAll('li');
for (var i = 0; i < li.length; i++) {
//立即执行函数
(function(i) {
li[i].addEventListener('click', function() {
console.log(i);
})
})(i);
}
</script>
- 直接将
for()
里面的变量var
改为let
即可(因为let
新增了块级作用域)
<ul>
<li>小明</li>
<li>小红</li>
<li>皮卡</li>
<li>杰尼龟</li>
<li>闪电</li>
</ul>
<script>
var li = document.querySelectorAll('li');
//循环绑定事件
//for循环是同步任务,会立即执行
for (let i = 0; i < li.length; i++) {
li[i].index = i;
//function是异步任务,会点击后再执行
li[i].addEventListener('click', function() {
console.log(this.index);
})
}
</script>
1.2、const
- 常量的使用–对象不能修改,但是可以改变对象内的属性
<script src="./js/vue.js"></script>
<script>
const obj = {
id: 102,
name: '小明同学',
}
1.修改对象内的属性是可以的(在原来的内存地址进行修改)
obj.name = '皮卡';
console.log(obj);
2.修改对象是不行的,直接报错(因为是将obj指向新的内存地址)
obj = {
id: 105,
name: '杰尼龟',
}
console.log(obj);
</script>
1.3、虚拟DOM
- 标签渲染时先渲染到
虚拟DOM
中,再渲染到浏览器上,(从虚拟DOM
往页面上渲染时,出于性能的考虑,会尽可能的复用已经存在的标签,而不会创建新的标签了) - 当我们不希望
VUE
出现重复利用的问题,可以给input
添加key
属性
三、组件化
- 组件化是将代码抽取成组件,可以实现代码的复用,使代码结构更加清晰
- 组件使用前一定要实例化Vue
3.1、注册组件的步骤
(1)创建组件的构造器 Vue.extends(参数一)
(2)注册组件 Vue.component(参数一,参数二)
,参数一不能使用驼峰命名
(3)使用组件
<body>
<div id="app">
<!-- 3.使用组件 -->
<mytest></mytest>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
// 1.构建组件的构造器
let test = Vue.extend({
template: `
<div>
<p>我是一个段落</p>
<p>什么?你不信我是个段落</p>
<p>???</p>
</div>
`
})
// 2.注册全局组件
Vue.component('mytest', test);
// 组件也需要实例化Vue
let app = new Vue({
el: '#app'
})
</script>
3.2、全局组件和局部组件
- 以上注册组件的方法是全局组件(在多个Vue实例下使用)
- 局部组件(components):
<body>
<div id="app">
<!-- 3.使用组件 -->
<mytest></mytest>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
// 1.构建组件的构造器
let test = Vue.extend({
template: `
<div>
<p>我是一个段落</p>
<p>什么?你不信我是个段落</p>
<p>???</p>
<h2>皮卡皮卡</h2>
</div>
`
})
// 组件也需要实例化Vue
let app = new Vue({
el: '#app',
components: {
//注册局部组件
mytest: test,
}
})
</script>
3.3、父子组件
- 在组件里注册组件(套娃开始)
- 当单独使用子组件时,会报错
<body>
<div id="app">
<!-- 3.使用组件 -->
<mytest2></mytest2>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
// 1.构建组件的构造器(子组件)
let test1 = Vue.extend({
template: `
<div>
<p>我是一个段落1111111111111</p>
<p>什么?你不信我是个段落</p>
<p>???</p>
<h2>皮卡皮卡</h2>
</div>
`
})
//1.构建组件的构造器(父组件)
let test2 = Vue.extend({
template: `
<div>
<p>我是一个段落2222222222</p>
<p>什么?你不信我是个段落</p>
<p>???</p>
<h2>皮卡皮卡</h2>
// 使用组件
<mytest1></mytest1>
</div>
`,
//注册组件
components: {
mytest1: test1
}
})
// 组件也需要实例化Vue
let app = new Vue({
el: '#app',
components: {
//注册局部组件
mytest2: test2,
}
})
</script>
3.4、使用语法糖来注册组件
- 直接把构造组件的构造器省略
<body>
<div id="app">
<!-- 3.使用组件 -->
<mytest></mytest>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
// 组件也需要实例化Vue
let app = new Vue({
el: '#app',
components: {
//注册局部组件
mytest: {
template: `
<div>
<p>我是一个段落</p>
<p>什么?你不信我是个段落</p>
<p>???</p>
<h2>皮卡皮卡</h2>
</div>
`
},
}
})
</script>
3.5、组件抽取模板
- 因为按照语法糖的写法会很混乱,所以需要将组件抽取出来
<body>
<div id="app">
<!-- 3.使用组件 -->
<mytest></mytest>
</div>
<template id="test">
<div>我是个div标签</div>
</template>
</body>
<script src="./js/vue.js"></script>
<script>
// 组件也需要实例化Vue
let app = new Vue({
el: '#app',
components: {
//注册局部组件
mytest: {
template: '#test',
},
}
})
</script>
3.6、组件data是函数
- 组件不能访问Vue实例中的data,所以Vue组件应该有保存数据的地方,是注册组件里的data函数
- 子组件不能访问父组件或Vue实例中的数据
3.7、组件通信-父传子
- 组件通信-父传子是父组件从后台请求数据,再将数据传递给子组件展示
- 通过props向子组件传递数据
- 通过事件向父组件传递消息
- 将父组件的数据传递给子组件,如下所示:
<body>
<div id="app">
<!-- 将movies传给了cpnmovie -->
<cpn :cpnmovie="movies"></cpn>
</div>
<template id="test">
<ul>
<li v-for="item in cpnmovie">{{item}}</li>
</ul>
</template>
</body>
<script src="./js/vue.js"></script>
<script>
// 注册组件,父传子props
let cpn = {
template: '#test',
props: ['cpnmovie'],
data() {
return {}
}
};
// 组件也需要实例化Vue
let app = new Vue({
el: '#app',
data: {
movies: ['足球少年', '甄嬛传', '如懿传'],
},
// 当注册全局组件时,也需要在实例对象中写components
components: {
cpn
}
})
</script>
3.8、组件通信-子传父
- 组件通信-子传父是子组件做的一些触发事件,可以向父组件请求数据
- 当子组件有东西发给父组件,使用
this.$emit(自定义,参数);
<body>
<!-- 父组件的模板 -->
<div id="app">
<!-- @itemClick监听过来的事件,cpnClick是处理事件 -->
<cpn @item-click="cpnClick"></cpn>
</div>
<!-- 子组件的模板 -->
<template id="test">
<div>
<!-- 需要监听按钮的点击,点击的时候拿到item,再传递给父组件 -->
<button v-for="item in catag" @click="btnClick">{{item.name}}</button>
</div>
</template>
</body>
<script src="./js/vue.js"></script>
<script>
//子组件
let cpn = {
template: '#test',
data() {
return {
catag: [{
id: 1,
name: '热门推荐'
}, {
id: 2,
name: '家电家具'
}, {
id: 3,
name: '畅销女装'
}, {
id: 4,
name: '数码电玩'
}, ]
}
},
methods: {
btnClick(item) {
//将子组件的ID传递给父组件,父组件要接收这个发射事件
this.$emit('item-click', item);
}
}
}
//父组件
let app = new Vue({
el: '#app',
components: {
cpn
},
methods: {
cpnClick() {
console.log('cpnClick');
}
}
})
3.9、组件通信-结合双向绑定(v-model)?(64-66)
- 当向通过
v-model
双向绑定某一个东西 的时候,不要绑定到props
上面 - 如下图所示:当直接显示时可以
props
,但是要修改时要加个中介data()
- 如下所示的目的:当改变值时,实现双向绑定的修改,并影响父组件
3.10、父组件访问子组件
- 父组件访问子组件:
$refs
;子组件直接访问父组件$parent
<body>
<div id="app">
<cpn></cpn>
<cpn ref="aaa"></cpn>
<cpn></cpn>
<button @click="btnClick">点击</button>
</div>
<template id="test">
<div>
<div>我是子组件</div>
</div>
</template>
</body>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
methods: {
btnClick() {
console.log(this.$refs.aaa.name);
}
},
components: {
cpn: {
template: '#test',
data() {
return {
name: '我是子组件的name'
}
}
}
}
})
</script>
3.11、补充-最纯粹的组件
四、插槽-slot
- 组件的插槽是为了让组件更具有扩展性
- 实例应用:京东的移动端导航栏,使用插槽更加方便
- 插槽在子模版中定义,在负组件中使用
<body>
<div id="app">
<cpn><button>按钮</button></cpn>
<cpn><span>我是段落</span></cpn>
<cpn><div>我是div标签</div></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="test">
<div>
<div>我是子组件的模板</div>
<!-- 也可以在插槽中设置默认值 -->
<slot></slot>
</div>
</template>
</body>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
msg: '我是父组件的数据'
},
components: {
cpn: {
template: '#test',
}
}
})
</script>
- 当有多个插槽需要替换时,就需要为每个插槽指定name
五、模块化开发
- 在之前多个JS文件组织的时候,会出现全局变量命名冲突的问题;而且多个JS文件在维护的时候,可能会导致一些灾难性的问题
- 常见的模块化规范:CommonJS,还有ES6的Modules
- 模块化的两个核心:导入和导出;
(1)CommonJS:导出:module.exports={}
,导入:const xx=require(文件路径)
(2)ES6:导出export{}
,导入import { name, age } from "./test1.js"
(导入的名字必须要与导出的名字一致)
let name = "小明test1";
let age = 23;
//1.导出方式一
export {
name,
age
};
//导出方式二
export let name = "小明导出方式二";
(3)export defalut
:一个模块中包含某种功能,我们不给功能命名,而是希望导入者来命名(这样可以让导入与导出的名字不一致
)
(4)export default
在同一个模块中,只能出现一次
//导出
export default {
name,
age
}
//导入 ,可以不加{}
import name from './test1.js'
六、webpack
- webpack是前端模块化打包工具,可以将ES6,jss,css模块化打包,然后部署搭到服务器上,相比起gulp来说,webpack更强调模块化开发管理,还有一些文件压缩,预处理的功能
- webpack打包工具需要npm包管理器来管理,但是这些的前提是有node运行环境