一、v-model使用和原理
1、v-model的基本使用
v-model用来实习那表单元素和数据的
双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
<h1>{{message}}</h1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
}
})
</script>
</body>
</html>
2、v-model的原理
v-bind绑定一个value属性
v-on指令给当前元素绑定input事件
(1)方式一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" :value="message" @input="valueChange">
<h1>{{message}}</h1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
methods: {
valueChange(event) {
this.message = event.target.value
}
}
})
</script>
</body>
</html>
(2)方式二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" :value="message" @input="message = $event.target.value">
<h1>{{message}}</h1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
}
})
</script>
</body>
</html>
3、v-model结合radio类型
这里就不需要给2个input加相同的name,自己会互斥
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<label for="male">
<input type="radio" id="male" v-model="sex" value="男">男
</label>
<label for="female">
<input type="radio" id="female" v-model="sex" value="女">女
</label>
<h1>你选择的性别:{{sex}}</h1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
sex: '男'
}
})
</script>
</body>
</html>
4、v-model结合checkbox类型
(1)checkbox单选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
</label>
<h2>你选择的是:{{isAgree}}</h2>
<button :disabled="!isAgree">下一步</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
isAgree: false
}
})
</script>
</body>
</html>
(2)checkbox多选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="checkbox" v-model="habbies" value="足球">足球
<input type="checkbox" v-model="habbies" value="蓝球">蓝球
<input type="checkbox" v-model="habbies" value="排球">排球
<input type="checkbox" v-model="habbies" value="桌球">桌球
<h2>你的爱好是:{{habbies}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
habbies: []
}
})
</script>
</body>
</html>
5、v-model结合select类型
(1)select单选
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<select name="" id="" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="榴莲">榴莲</option>
<option value="葡萄">葡萄</option>
</select>
<h2>你选择的水果是:{{fruit}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
fruit: '香蕉'
}
})
</script>
</body>
</html>
(2)select多选
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<select name="" id="" v-model="fruits" multiple>
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="榴莲">榴莲</option>
<option value="葡萄">葡萄</option>
</select>
<h2>你选择的水果是:{{fruits}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
fruits: []
}
})
</script>
</body>
</html>
6、input中的值绑定
通过v-bind:value动态给value绑定值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<label v-for="item in allHabbies" :for="item">
<input type="checkbox" :value="item" v-model="hobbies">{{item}}
</label>
<h2>你的爱好是: {{hobbies}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
hobbies: [],
allHabbies: ['篮球','足球', '桌球']
}
})
</script>
</body>
</html>
7、v-model修饰符的使用
(1)lazy
数据在失去焦点或者会车时才会更新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model.lazy="message">{{message}}
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
}
})
</script>
</body>
</html>
(2)number
让输入框的的内容自动转成数字类型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="number" v-model.number="age">
<h2>{{age}}--{{typeof age}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
age: 0
}
})
</script>
</body>
</html>
(3)trim
过滤内容左右两边的空格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model.trim="name">
<h2>你输入的名字:{{name}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
name: ''
}
})
</script>
</body>
</html>
二、组件
1、注册组件的基本步骤
-
1、创建组件构造器
-
2、注册组件
-
3、使用组件
2、组件化的基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script src="../js/vue.js"></script>
<script>
// 1、创建组件构造器对象
const cpnC = Vue.extend({
template: `
<div>
<h2>标题</h2>
<p>内容一</p>
<p>内容二</p>
</div>
`
});
// 2、注册组件
Vue.component('my-cpn', cpnC);
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
}
})
</script>
</body>
</html>
3、全局组件和局部组件
(1)全局组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<div id="app1">
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
const cpnC = Vue.extend({
template: `
<div>
<h2>标题</h2>
<p>内容一</p>
<p>内容二</p>
</div>
`
});
Vue.component('cpn', cpnC);
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
}
});
const app1 = new Vue({
el: '#app1',
data: {
message: 'hello,Vue'
}
})
</script>
</body>
</html>
(2)局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<div id="app1">
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
const cpnC = Vue.extend({
template: `
<div>
<h2>标题</h2>
<p>内容一</p>
<p>内容二</p>
</div>
`
});
// Vue.component('cpn', cpnC);
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
components: {
cpn: cpnC
}
});
const app1 = new Vue({
el: '#app1',
data: {
message: 'hello,Vue'
}
})
</script>
</body>
</html>
4、父组件和子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 1、第一个组件构造器(子组件)
const cpnC1 = Vue.extend({
template: `
<div>
<h2>标题一</h2>
<p>内容一</p>
<p>内容二</p>
</div>
`
});
// 2、第二个组件构造器(父组件)
const cpnC2 = Vue.extend({
template: `
<div>
<h2>标题二</h2>
<p>内容一</p>
<p>内容二</p>
<cpn1></cpn1>
</div>
`,
components: {
cpn1: cpnC1
}
});
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
components: {
cpn2: cpnC2
}
})
</script>
</body>
</html>
5、组件的语法糖注册方式
省去了Vue.extend()的步骤,而是可以直接使用一个对象来替代
(1)全局注册
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn1></cpn1>
</div>
<script src="../js/vue.js"></script>
<script>
Vue.component('cpn1',{
template: `
<div>
<h2>标题</h2>
<p>内容一</p>
<p>内容二</p>
</div>
`
});
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
}
})
</script>
</body>
</html>
(2)局部注册
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn1></cpn1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
components: {
'cpn1': {
template: `
<div>
<h2>标题</h2>
<p>内容一</p>
<p>内容二</p>
</div>
`
}
}
})
</script>
</body>
</html>
6、组件模板的分离写法
(1)通过script标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<script type="text/x-template" id="cpn">
<div>
<h2>标题一</h2>
<p>内容一</p>
<p>内容二</p>
</div>
</script>
<script src="../js/vue.js"></script>
<script>
Vue.component('cpn',{
template: '#cpn'
});
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
})
</script>
</body>
</html>
</body>
</html>
(2)通过template标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>标题一</h2>
<p>内容一</p>
<p>内容二</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
Vue.component('cpn',{
template: '#cpn'
});
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
})
</script>
</body>
</html>
</body>
</html>
7、组件中的数据存放
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>标题一{{title}}</h2>
<p>内容一</p>
<p>内容二</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
Vue.component('cpn',{
template: '#cpn',
data() {
return {
title: 'yyy'
}
}
});
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
})
</script>
</body>
</html>
</body>
</html>
8、组件data为什么是函数
用函数每次都会生成新的内存对象,从而每个组件都互不关联
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h1>当前计数:{{counter}}</h1>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
Vue.component('cpn',{
template: '#cpn',
data() {
return {
counter: 0
}
},
methods: {
increment() {
this.counter++
},
decrement() {
this.counter--
}
}
});
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
}
})
</script>
</body>
</html>
9、父子组件的通信
(1)通信方法
-
1、通过props向子组件传递数据
-
2、通过事件向父组件发送消息($emit Events)
(2)父组件向子组件传递数据
props验证支持的数据类型:String、Number、Boolean、Array、Object、Date、Function、Symbol
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn :cmovies="movies" :cmessage="message"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
{{cmessage}}
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
// props: ['cmovies', 'cmessage'],
props: {
// 1、类型限制
// cmovies: Array,
// cmessage: String
// 2、提供默认值
cmessage: {
type: String,
default: 'aaaa',
required: true //必须传
},
//类型是对象或数组时,默认值必须是一个函数
cmovies: {
type: Array,
default() {
return {}
}
}
},
data() {
return {}
}
}
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
movies: ['海贼王', '火影忍者','海尔兄弟']
},
components: {
cpn
}
})
</script>
</body>
</html>
(3)组件通信-父传子(props中的驼峰标识)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn :c-info="info"></cpn>
</div>
<template id="cpn">
<div>
<h1>{{cInfo}}</h1>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
props: {
cInfo: {
type: Object,
default() {
return {}
}
}
}
};
const app = new Vue({
el: '#app',
data: {
info: {
name: 'yyy',
age: 18
}
},
components: {
cpn
}
})
</script>
</body>
</html>
(4)组件通信-子传父(自定义事件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--父组件-->
<div id="app">
<cpn @itemclick="cpnClick"></cpn>
</div>
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 子组件
const cpn = {
template: '#cpn',
data() {
return {categories: [
{id:'a', name:'热门推荐'},
{id:'a', name:'手机数码'},
{id:'a', name:'电脑办公'}
]
}},
methods: {
btnClick(item){
//发射自定义事件
this.$emit('itemclick',item)
}
}
};
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn
},
methods: {
cpnClick(item) {
console.log('cpnClick',item);
}
}
})
</script>
</body>
</html>
(5)组件通信-父子通信案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"></cpn>
</div>
<template id="cpn">
<div>
<h2>props:{{number1}}</h2>
<h2>data:{{dnumber1}}</h2>
<!--<input type="text" v-model="dnumber1">-->
<input type="text" :value="dnumber1" @input="num1Input">
<h2>props:{{number2}}</h2>
<h2>data:{{dnumber2}}</h2>
<!--<input type="text" v-model="dnumber2">-->
<input type="text" :value="dnumber2" @input="num2Input">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 2
},
methods: {
num1change(value) {
this.num1 = parseInt(value)
},
num2change(value) {
this.num2 = parseInt(value)
}
},
components: {
cpn: {
template: '#cpn',
props: {
number1: Number,
number2: Number
},
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2
}
},
methods: {
num1Input(event) {
// 1、将input中的value赋值到dnumber中
this.dnumber1 = event.target.value;
// 2、为了让父组件可以修改值,发出一个事件
this.$emit('num1change', this.dnumber1);
// 3、同时修改dnumber2的值
this.dnumber2 = this.dnumber1 * 100;
this.$emit('num2change', this.dnumber2)
},
num2Input(event) {
this.dnumber2 = event.target.value;
this.$emit('num2change', this.dnumber2)
//同时修改dnumber1的值
this.dnumber1 = this.dnumber2 / 100;
this.$emit('num1change', this.dnumber1)
}
}
}
}
})
</script>
</body>
</html>
(6)组件访问-父访问子-children-refs
一般使用refs,当需要访问所有的时候使用children
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>
<cpn ref="aaa"></cpn>
<button @click="btnClick">按钮</button>
</div>
</div>
<template id="cpn">
<div>我是子组件</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
methods: {
btnClick() {
console.log(this.$children);
// 1、$children
// this.$children[0].showMessage();
// 2、$refs
console.log(this.$refs.aaa.showMessage());
}
},
components: {
cpn: {
template: "#cpn",
methods: {
showMessage() {
console.log('showMessage');
}
}
}
}
})
</script>
</body>
</html>
三、组件化高级
1、slot-插槽的基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn><span>1111</span></cpn>
</div>
<template id="cpn">
<div>
<h1>我是子组件</h1>
<slot><button>按钮</button></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
</body>
</html>
2、slot-具名插槽的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn><span slot="center">标题</span></cpn>
</div>
<template id="cpn">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue'
},
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
</body>
</html>
3、什么是编译作用域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<p>哈哈</p>
<button v-show="isShow">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
isShow: true
},
components: {
cpn: {
template: '#cpn',
data() {
return {
isShow: false
}
}
}
}
})
</script>
</body>
</html>
4、作用域插槽案例
父组件替换插槽的标签,但是内容由子组件来提供
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn>
<template slot-scope="slot">
<!--<span v-for="item in slot.data">{{item}} - </span>-->
<span>{{slot.data.join(' - ')}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot :data="pLanguages"> <!--data可以自定义修改-->
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello,Vue',
},
components: {
cpn: {
template: '#cpn',
data() {
return {
pLanguages: ['JavaScript', 'C++', 'Java', 'C#', 'Python']
}
}
}
}
})
</script>
</body>
</html>
四、前端模块化
1、ES6实现模块化
(1)index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="aaa.js" type="module"></script>
<script src="bbb.js" type="module"></script>
<script src="mmm.js" type="module"></script>
</body>
</html>
(2)aaa.js
var name = '小明';
var age = 18;
var flag = true;
function sum(num1, num2) {
return num1 + num2
}
if (flag) {
console.log(sum(20, 30));
}
// 1、到处方式一
export {
flag,sum
}
// 2、导出方式二
export var height = 1.88
//3、到处函数/类
export function mul(num1, num2) {
return num1 + num2
}
(3)bbb.js
var name = '小红';
var flag = false;
(4)mmm.js
import {flag, sum} from './aaa.js';
if (flag) {
console.log('小明');
console.log(sum(20, 30));
}
import addr from './aaa.js';
console.log(addr);
// 统一导入
// import * as aaa from './aaa.js'
// console.log(aaa.flag);