前端框架
框架和库
库:库更侧重于某一个功能点,库与库之间没有排他性,一个项目中,跨域引入多个库混合使用。jQuery、lodash
框架:框架给项目提供一套完整的解决方案,框架和框架之间一般不会混合使用。
VUEjs\React\Angular
Angular
诞生于2009年React
诞生于2013年,起源于facebook的内部项目--Instagram。VUEjs
诞生于2014年,尤雨溪开发。vue基础语法
vue实例
const vm = new Vue({});
1.data数据
data用于设置当前vue实例中所有需要用到的数据。data属性的值只有两种情况:对象、返回对象的函数。
const vm = new Vue({
data:{
//数据
}
});
const vm = new Vue({
data:function(){
return {
//数据
}
}
});
注意:在后续学习完组件以后,组件中的data就只能返回对象的函数了。
el
el 属性用于指定当前vue实例的挂载目标。换句话说el属性就是用来指定vue实例的作用范围。el的属性值是一个字符串,用于设置挂载目标节点的选择器。
注意:不要将body设置为挂载目标,因为vue最终渲染成功后会将挂载目标元素给替换掉。
模板语法(数据渲染)
在挂载目标范围内,通过{{}}双大括号的语法,可以将vue实例中的数据渲染到页面上。html
<div id="app">
<h1>{{msg + student.name}}</h1>
<h3>{{flag ? 'hello':'world'}}</h3>
{{num}}
</div>
vue
const vm = new Vue({
el:'#app',
data:function(){
return {
msg:'hello world',
num:100,
student:{
name:'starnight',
age:20
},
flag:true
}
}
});
事件处理
事件监听vue中提供了一个v-on指令,用来设置事件监听
<button v-on:click="handleClick">按钮</button>
事件处理函数
vue中提供了一个methods属性,用来设置vue中所有需要用到的方法。
const vm = new Vue({
methods:{
handleClick(){
console.log('123123');
}
}
});
响应式
当一个vue实例创建时,它将data对象中的所有的属性(数据)加入到vue的响应式系统中。当data中的数据值发生改变时,视图(页面)会自动去“响应”数据的变化,立即更新为最新的数据。
指令
vue中提供了一系列以v-on开头的属性,我们把这些属性称之为“指令”。v-text
v-text也可以用于数据渲染,该指令所对应的数据,会将标签中原本的数据给覆盖掉。<h2 v-text="msg">100</h2>
//渲染之后显示的时msg的值
v-html
v-html也可以用于数据渲染,它和v-text、双大括号的区别在于,v-html可以识别数据中的HTML代码。html
<div id="app">
<h1 v-html="msg"></h1>
</div>
new Vue({
el:'#app',
data(){
return{
msg:'<a href="#">hello</a>'
}
}
})
v-show
v-show指令通过属性值的真或假,来设置元素的display属性。html
<div id="app">
<h1 v-show="isShow">{{msg}}</h1>
<button v-on:click="isShow = !isShow">显示/隐藏</button>
</div>
new Vue({
el:'#app',
data(){
return{
msg:'<a href="#">hello</a>',
isShow:true
}
}
})
v-on
用于绑定事件监听器简写@
<button @click="isShow = !isShow">显示/隐藏</button>
v-bind
当我们需要给标签身上的属性设置动态的数据时,就需要用过v-bind来设置该属性。简写:
<a v-bind:href="link">百度</a>
//简写<a :href="link">百度</a>
new Vue({
el:'#app',
data(){
return{
msg:'<a href="#">hello</a>',
isShow:true
link:'https://www.baidu.com'
}
}
})
条件渲染
vue中提供了v-if、v-else、v-else-if来实现条件渲染。v-if和v-show的区别:
v-if是通过控制元素是否在DOM节点中渲染,来决定元素的显示或隐藏;
v-show是通过控制元素的display的css样式,来决定元素的显示或隐藏。
当我们需要频繁的进行显示/隐藏的切换时,用v-show,否则用v-if。
template标签
其内容隐藏在客户端之外,该内容在加载页面时是不会呈现、不会渲染出任何信息的。相当于自带属性:template{display:none;}
列表渲染
vue中提供了v-for来实现列表渲染。根据源数据多次呈现元素或模板块。
<div v-for="item in items">
{{ item.text }}
</div>
v-for注意点:
1.使用对象
可以针对于数组和对象;
2.key属性
为了跟踪到v-for循环出来的每个节点,则需要为v-for所在的节点提供一个唯一的key属性。key属性的类型只能为string类型或number类型。
3.应用场景
在项目中,会遇到多层v-for嵌套的情况,这时,key的值不能全部取相应的index,不然会报错。由于key的属性可以为string或number,所以可以取对象或数组中为string类型的值作为key属性。
通过v-for渲染出来每一个元素身上都需要添加一个唯一的key属性。
注意:不推荐在同一元素上使用v-if和v-for。
练习
购物车
<div id="app">
<table>
<thead>
<tr>
<th>商品编号</th>
<th>商品名称</th>
<th>商品单价</th>
<th>商品数量</th>
<th>商品总价</th>
<th>商品操作</th>
</tr>
</thead>
<tbody>
<tr v-if="goodsData.every(item => item.count == 0)">
<td>购物车为空</td>
</tr>
<tr v-for="item in goodsData" :key="item._id">
<td>{{item._id}}</td>
<td>{{item.name}}</td>
<td>{{item.price}}</td>
<td>
<button @click="item.count--">-</button>
<span>{{item.count}}</span>
<button @click="item.count++">+</button>
</td>
<td>{{item.price * item.count}}</td>
<!-- 删除 -->
<td><button @click="goodsData.splice(index,1)">删除</button></td>
</tr>
</tbody>
</table>
<p>合计:{{totalPrice()}}</p>
</div>
<script src="./js/vue-2.4.0.js"></script>
<script>
new Vue({
el:'#app',
data(){
return {
goodsData:[
{ _id:1,name:'苹果',price:'10',count:20},
{ _id:2,name:'香蕉',price:'20',count:10},
{ _id:3,name:'梨',price:'15',count:22},
]
}
},
methods:{
//计算总价
totalPrice(){
const totalPrice = 0;
return this.goodsData.reduce((sum,item) => {
return sum + item.price * item.count;
},0);
}
}
})
</script>
计算属性和侦听器
计算属性
computed当我们需要对原数据(data)进行一些额外的操作,希望在原数据的基础之上得到一些新数据,但同时又不希望改变原数据。这种情况下,我们会选择用计算属性。
原
export default {
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
}
}
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
计算属性
export default {
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
},
computed: {
// a computed getter
publishedBooksMessage() {
// `this` points to the component instance
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
}
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
计算属性的缓存
计算属性的结果会在第一次计算完成后缓存下来,在后续的使用中,只要原数据没有发生变化,计算属性就不会再重新计算。每一次的使用都是读取缓存中的结果。
一旦计算属性中依赖的原数据发生变化,计算属性就会重新计算,也就是说,计算属性所对应的方法会重新调用。
计算属性的getters和setters
该选项接收一个对象,其中键是计算属性的名称,值是一个计算属性 getter,或一个具有 get 和 set 方法的对象 (用于声明可写的计算属性)。所有的 getters 和 setters 会将它们的 this 上下文自动绑定为组件实例。
<div id="app">
<h1>{{num}}</h1>
<button @click="num ='star night'">修改</button>
</div>
<script src="./js/vue-2.4.0.js"></script>
<script>
new Vue({
el:'#app',
data(){
return{
xing: 'st',
ming: 'ni'
}
},
//计算属性
computed:{
num:{
get(){
return this.xing + ' ' + this.ming;
},
set(val){
this.xing = val.split(' ')[0];
this.ming = val.split(' ')[1];
}
}
}
})
</script>
todolist练习
<!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>Document</title>
<style>
.done{
color: red;
text-decoration: line-through;
}
.btns>* {
margin-right: 10px;
}
</style>
</head>
<body>
<div id="app">
<ul>
<!-- <li>html(false)</li>
<li>css(true)</li>
<li>js(false)</li> -->
<!-- <li class="done" v-for="(item,index) in listData" :key="index">
{{item.text}}
<span v-if="item.done">(完成)</span>
<span v-else>(未完成)</span>
</li> -->
<template v-for="(item,index) in filterListData">
<li class="done" v-if="item.done" @click="item.done = !item.done">{{item.text}}</li>
<li v-else @click="item.done = !item.done">{{item.text}}</li>
<!-- @click="item.done = false/true" -->
</template>
</ul>
<div class="btns">
<template v-for="item in btns">
<span v-if="item == current" >{{item}}</span>
<a href="#" v-else @click="current = item">{{item}}</a>
</template>
<span>{{doneTotal}}/{{listData.length}}</span>
</div>
</div>
<script src="./js/vue-2.4.0.js"></script>
<script>
new Vue({
el:'#app',
data(){
return {
listData:[
{ text:'html',done:false},
{ text:'css',done:true},
{ text:'js',done:false},
],
btns:['all','done','active'],
current:'all'
}
},
computed:{
filterListData(){
switch(this.current){
case 'done':return this.listData.filter(item =>item.done);
case 'active':return this.listData.filter(item =>!item.done);
default:return this.listData;
}
},
doneTotal(){
return this.listData.filter(item => item.done).length;
}
}
})
</script>
</body>
</html>
侦听器
vue中提供了watch属性,用来侦听data或computed中数据的变化。一旦侦听发生了改变,就会执行对应的侦听方法。 new Vue({
el:'#app',
data(){
return {
currentPage:1
}
},
//侦听器(侦听属性)
watch:{
currentPage(newValue,oldValue){
//当curentPage发生变化时,该函数会被调用
}
}
})
侦听引用数据类型
new Vue({
el:'#app',
data(){
return {
pageData:{
currentPage:1
}
}
},
//侦听器(侦听属性)
watch:{
'pageData.currentPage'(newValue,oldValue){
//当curentPage发生变化时,该函数会被调用
},
pageData:{
handler(newValue,oldValue){
//当pageData中的任意属性发生变化时,该函数会被调用
},
//深度侦听
deep:true
}
}
})
数据首次渲染时的侦听
默认情况下,watch只有在数据发生改变时才会触发侦听。但是,某些情况下,我们需要数据首次渲染时,也能够触发侦听函数。
new Vue({
el:'#app',
data(){
return {
currentPage:1
}
},
//侦听器(侦听属性)
watch:{
currentPage:{
hanler(newValue,oldValue){
//当curentPage发生变化时,该函数会被调用
},
//立即执行侦听
immediate:true
}
}
})
事件处理扩展语法(事件修饰符)
.stop
阻止单击事件继续传播
<a v-on:click.stop='doThis'></a>
.prevent
提交事件不再重载页面
<form v-on:submit.prevent='onSubmit'></form>
修饰符可以串联
<a v-on:click.stop.prevent="doThat"></a>
.capture
添加事件监听器时使用事件捕获模式
即内部元素触发的事件先在此处理,然后才交由内部元素进行处理
<div v-on:click.capture='doThis'>...</div>
class与style绑定
操作元素的class列表和内联样式是数据绑定的一个常见需求。我们可以用v-bind处理:只需要通过表达式计算出字符串结果即可。但是字符串拼接麻烦且容易出错。因此,在将v-bind用于class和style是,vue.js做了增强,表达式的结果类型除了字符串之外,还可以是对象或数组。对象语法
我们可以传给v-bind:class一个对象,动态地切换class
<div v-bind:class="{active:isActive}"></div>
数组语法
我们可以把一个数组传给v-bind:class,以应用一个class列表
<div v-bind:class="[activeClass,erroeClass]"></div>
vue中data:
data:{
cativeClass:'active',
erroeClass:'text-danger'
}
渲染为:
<div class="active text-danger"></div>
如果想根据条件切换列表中的class,可以用三元表达式
<div v-bind:class="[isActive ? activeClass:'',erroeClass]"></div>
绑定内联样式
对象语法v-bind:style的对象语法十分直观,看着非常像css,但其实是一个javascript对象。css属性名可以用驼峰或短横线(需要引号)分隔来命名
<div v-bind:style="{color:activeColor,fontSize:fontSize+'px'}"></div>
data:{
activeColor:'red',
fontSize:30
}
数组语法
v-bind:style的数组语法可以将多个样式对象应用到同一个元素上:
<div v-bind:style="[baseStyles,overridingStyles]"></div>
自动添加前缀
当v-bind:style使用需要添加浏览器引擎前缀的css属性时,如transform,vue.js会自动侦测并添加相应的前缀。
表单输入绑定
vue中提供了v-model指令用于表单元素。双向数据绑定
通过v-model绑定的元素身上,都具有双向数据绑定的功能。
双向数据绑定,指的是:页面由data中的数据渲染而来,当data中的数据发生改变时,页面会自动更新;当操作页面时,data中的数据也会随之改变。
v-model的使用
1.输入框在输入框中绑定v-model属性,就可以通过v-model的属性值,实时获取到用户输入的内容。
<input type="text" v-model="name">
data(){
return{
name:'starnight',
}
}
2.复选框
单个复选框
在单个复选框上绑定v-model属性,可以通过v-model属性值的true或false,来控制复选框的选中或未选中,同时,操作复选框的选中或未选中,也会同步更新v-model属性值的true或false。
<input type="checkbox" v-model="isChecked">
data(){
return{
isChecked:true
}
},
多个复选框
在多个复选框上绑定同一个v-model属性,通过判断复选框自己的value值是否在v-model的数组里面,来控制复选框的选中或未选中。同时,操作复选框的选中或未选中,也会同步更新复选框的value值在数组中添加或删除。
<input type="checkbox" value="eat" v-model="checkeds">吃饭
<input type="checkbox" value="sleep" v-model="checkeds">睡觉
<input type="checkbox" value="hit" v-model="checkeds">打豆豆
data(){
return{
checkeds:['sleep'],
}
},
3.单选框
在单选框上绑定v-model属性,通过判断单选框自己的value值是否和v-model的值是否相等,来控制单选框的选中或未选中。
<input type="radio" value="男" v-model="gender">男
<input type="radio" value="女" v-model="gender">女
data(){
return {
gender:'男',
}
},
4.下拉列表
在select身上绑定v-model属性,通过判断option的value值和v-model的值是否相等,来决定被选中的option。
<select v-model="city">
<option value="四川">四川</option>
<option value="上海">上海</option>
<option value="北京">北京</option>
<option value="云南">云南</option>
</select>
data(){
return{
city:'北京'
}
},
组件
组件的概念
通常一个应用会以一棵嵌套的组件树的形式来组织例如,可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
为了能在模板中使用,这些组件必须先注册以便vue能够识别。这里有两种组件的注册类型:全局注册和局部注册。
至此,我们的组件都只是通过vue.component全局注册的。
<body>
<div id="app">
<hello></hello>
<world></world>
</div>
<div id="root">
<hello></hello>
<my></my>
</div>
<script src="./js/vue-2.4.0.js"></script>
<script>
//全局注册组件(创建组件)(可以嵌套局部)
Vue.component('hello',{
//组件的模板(组件要显示的标签)
template:`
<div>
<h1>hello</h1>
<h2>hello</h2>
<world2></world2> //嵌套
<h3>hello</h3>
</div>
`
});
Vue.component('world2',{
template:`
<div>
<h1>star</h1>
</div>
`
})
Vue.component('my',{
template:`
<div>
<h1 @click='clickEvent'>{{newmsg}}</h1>
</div>
`,
data(){
return {
msg:'night'
}
},
computed:{
newmsg(){
return this.msg+' love';
}
},
methods:{
clickEvent(){
console.log('zyyzyy');
}
}
});
//局部注册组件(不能嵌套进全局)
new Vue({
el:'#app',
components:{
'world':{
template:`<p>star night</p>`
}
}
})
new Vue({
el:'#root'
})
</script>
</body>
prop
vue中为组件提供了一个props的属性,用于父组件向子组件传值。父组件传值
父组件中,可以通过给子组件设置属性的方式,来给子组件进行传值。
Vue.component('father',{
template:`
<div>
<child name="xinwan"></child>
</div>
`
})
Vue.component('child',{
props:['name'],
template:`<span>{{name}}</span>`
})
子组件接收值
子组件通过props属性,在数组中设置对应的属性名,来接收父组件传递的数据。(可以接收多个传递多个)
Vue.component('child',{
props:['name'],
template:`<span>{{name}}</span>`
})
传递的数据类型
当父组件向子组件传递数据时,除了传递字符串以外,其他所有数据类型都需要通过v-bind来进行传递。
Vue.component('father',{
template:`
<div>
<child name="xinwan" :age="20" :flag="true"></child>
</div>
`
})
对象形式的props
props可以通过设置成对象的形式,来进行props的验证。Vue.component('child',{
props:{
name:String, //name接收的数据类型为String
age:[Number,String], //age接收的数据类型为Number 或者 String
gender:{
type:String, //gender 接收的数据类型为String
dafault:'nv' // 当没有接收到gender属性值时,采用default的默认值‘nv’
},
friends:{
type:Object,
//default:() => {return () }
default:() => ({}) //当默认值为数组或对象时,要以函数返回值的形式来设置默认值。
}
}
})
自定义事件
基础语法
在父组件的methods属性中定义事件的方法,然后在调用子组件时,通过@自定义名称=方法名来向子组件传递自定义事件。//父组件
Vue.component('father',{
template:`
<div>
<child @hello="hello"></child>
</div>
`,
methods:{
hello() {
console.log('hello');
},
}
})
子组件通过@事件类型="$emit('自定义事件名称')"来触发父组件传递的自定义事件。
//子组件
Vue.component('child',{
template:`
<div>
<h1 @click="$emit('hello')">child</h1>
</div>
`
})
自定义事件的使用场景
1.子组件修改父组件的数据在父组件中定义一个修改父组件数据的方法,然后通过自定义事件将该方法传递给子组件,让子组件来触发该方法。
Vue.component('father',{
template:`
<div>
<child @add="add"></child>
</div>
`,
data() {
return {num:100}
},
methods:{
add(){
this.num++;
},
}
})
//子组件
Vue.component('child',{
template:`
<div>
<button @click="$emit('add')">+1</button>
</div>
`
})
2.子组件传值给父组件
当子组件想要将数据传递给父组件时,通过调用父组件的方法,来进行数据的传递。
Vue.component('father',{
template:`
<div>
<child @add="add"></child>
</div>
`,
data() {
return {num:100}
},
methods:{
add(newNum1,newNum2){
this.num += newNum1 + newNum2;
},
}
})
$emit()的第二个参数,用来向父组件传递数据
//子组件
Vue.component('child',{
template:`
<div>
<button @click="$emit('add',200,300)">+1</button>
</div>
`
})
插槽
vue中提供了slot来作为插槽使用。插槽内容
从组件外部往组件内部的插槽添加内容。<cpn><h2>插槽内容</h2></cpn>
Vue.component('cpn',{
tempalte:`
<div>
<slot></slot>
</div>
`
});
后备内容(插槽的默认值)
当我们使用组件时,没有给插槽传递内容,默认情况下,插槽内容为空。但是我们也可以自己手动去给插槽设置默认值,即当没有给插槽传递数据时,页面就显示插槽的默认值。<cpn></cpn>
Vue.component('cpn',{
template:`
<div>
<slot>插槽的默认值</slot>
</div>
`
});
具名插槽
当一个组件中,有多个插槽时,我们可以通过name属性给插槽设置名字。<cpn>
<template v-slot:header>
<h1>头部</h1>
</template>
<template v-slot:footer>
<h1>尾部</h1>
</template>
</cpn>
Vue.component('cpn',{
template:`
<div>
<slot name="header"></slot>
<slot name="footer"></slot>
</div>
`
});
作用域插槽
当插槽中渲染的数据,是由插槽所在的子组件提供,但是插槽显示的标签是由父组件提供,这种情况下我们就需要用到作用域插槽。Vue.component('father',{
template:`
<div>
<child v-slot="slotProps">
<ul>
<li v-for="item in slotProps.students" :key="item">{{item}}</h1>
</ul>
</child>
<chile v-slot="slotProps">
<ol>
<li v-for="item in slotProps.students" :key="item">{{item}}</li>
</ol>
</child>
</div>
`
});
Vue.component('child',{
data(){
return {
students:['张三','李四','王五']
}
},
template:`
<div>
<h3>学生列表</h3>
<slot :students="students"></slot>
</div>
`
});
生命周期函数
new Vue({
el:'#app',
data(){
return {
msg:'star'
}
},
beforeCreate(){
console.log('创建前');
},
created(){
console.log('创建完成');
},
beforeMount(){
console.log('挂载前');
},
mounted(){
console.log('挂载完成');
},
beforeUpdate(){
console.log('数据更新前');
},
updated(){
console.log('更新完成');
},
beforeDestroy(){
console.log('销毁前');
},
destroyed(){
console.log('销毁完成');
}
})
created\mounted:页面初始化时向服务端发起请求。
动态组件
Vue.component('tabs',{
data(){
return {
current:'home'
}
},
template:`
<div>
<div>
<button @click="current = 'home'">home</button>
<button @click="current = 'about'">about</button>
<button @click="current = 'psots'">posts</button>
</div>
<div>
<keep-alive>
<component :is="current"></component>
</keep-alive>
</div>
</div>
`
})
Vue.component('home',{
template:`
<h1>home的组件内容</h1>
`
})
Vue.component('about',{
template:`
<h1>about的组件内容</h1>
<input type="text"/>
`
})
Vue.component('psots',{
template:`
<h1>psots的组件内容</h1>
`
})