*
1. 简单的一个购物车小案例
<!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 src="./js/vue.min.js"></script>
<style>
body {
text-align: center;
margin-top: 120px;
}
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th, td {
padding: 8px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
th {
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}
</style>
</head>
<body>
<div id='app'>
<div v-if='books.length'>
<table>
<thead>
<tr>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<!-- 过滤器 | 后面是过滤器的方法 -->
<td>{{item.price | showPrice}}</td>
<td>
<button @click='decrement(index)' :disabled='item.count <= 1'>-</button>
{{item.count}}
<button @click='increment(index)' :disabled='item.count >= 10'>+</button>
<button @click='removeHandle(index)'>移除</button>
</td>
</tr>
</tbody>
</table>
<h2>总价格{{totalPrice | showPrice}}</h2>
</div>
<div v-else>
购物车为空
</div>
</div>
</body>
<script>
const app = new Vue({
el: '#app',
filters: {
showPrice(price) {
// {{price.toFixed(2)}} 保留两位小数
return `¥${price.toFixed(2)}`
}
},
computed: {
totalPrice() {
let totalPrice = 0
/* for(let i = 0; i < this.books.length; i++) {
totalPrice += this.books[i].price * this.books[i].count
} */
for(let item of this.books) {
totalPrice += item.price * item.count
}
return totalPrice
}
},
methods: {
increment(index) {
this.books[index].count++
},
decrement(index) {
this.books[index].count--
},
removeHandle(index) {
this.books.splice(index,1)
}
},
data: {
books: [{
id: 1,
name: '《算法导论》',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 2,
name: '《UNIX编程艺术》',
date: '2006-2',
price: 59.00,
count: 1
},
{
id: 3,
name: '《编程珠玑》',
date: '2008-10',
price: 39.00,
count: 1
},
{
id: 4,
name: '《代码大全》',
date: '2006-3',
price: 128.00,
count: 1
}]
}
})
</script>
</html>
*
2. Javascript高阶函数的使用
- 作用:对数组中所有的内容进行汇总
let arr = [12.2, 45, 10.85, 36, 17]
let totalFilterAndMap = arr.filter((n) => n < 30).map((n) => n *2)
// [ 24.4, 21.7, 34 ]
console.log(totalFilterAndMap)
let totelReduce = arr.reduce((preValue, nextValve) => preValue + nextValve, 0)
// 121.05
console.log(totelReduce)
*
3. Vue.js 中使用 v-model 绑定表单
3.1. 绑定radio
<label for="male">
<input type="radio" id="male" value="男" v-model="sex" />男
</label>
<label for="female">
<input type="radio" id="female" value="女" v-model="sex" />女
</label>
<h2>您选的性别是:{{sex}}</h2>
data: {
sex: '女', // 默认值
}
3.2. 绑定 checkbox
-
checkbox 单选框
<label for="agreement"> <input type="checkbox" id="agreement" v-model="agreement"> </label> 同意:{{agreement}} <button :disabled="!agreement">下一步</button> data: { agreement: false, // 单选框 }
-
checkbox 多选框
<input type="checkbox" value="篮球" v-model="hobbies">篮球 <input type="checkbox" value="足球" v-model="hobbies">足球 <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球 <input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球 <input type="checkbox" value="排球" v-model="hobbies">排球 <h2>您的爱好是:{{hobbies}}</h2> data: { hobbies: [] // 多选框 }
3.3. 绑定 select
<select name="fruit" id="" v-model="fruit">
<option value="苹果">苹果</option>
<option value="橘子">橘子</option>
<option value="香蕉">香蕉</option>
<option value="西瓜">西瓜</option>
<option value="榴莲">榴莲</option>
</select> <br />
<h2>您喜欢的水果是:{{fruit}}</h2>
data: {
fruit: '橘子'
}
<select name="fruits" id="" v-model="fruits" multiple>
<option value="苹果">苹果</option>
<option value="橘子">橘子</option>
<option value="香蕉">香蕉</option>
<option value="西瓜">西瓜</option>
<option value="榴莲">榴莲</option>
</select> <br />
<h2>您喜欢的水果是:{{fruits}}</h2>
data: {
fruits: ['西瓜', '橘子']
}
3.4. input 中的值绑定
- 可以将服务器返回的供用户选择 数据动态的渲染出来
<label v-for="item in orginalHobbies" :for="item">
<input type="checkbox" :value="item" :id="item" v-model='hobbies'>{{item}}
</label>
data: {
hobbies: [], // 多选框
orginalHobbies: ['篮球', '乒乓球', '台球', '高尔夫球']
}
3.5. v-model 修饰符的使用
-
lazy 懒加载(增加用户体验, 处理加载频率过高的问题) 输完内容后按回车或者失去焦点时在绑定
<input type="text" v-model.lazy="message"> {{message}} data: { message: '' }
-
修饰符 number
作用:将输入框中的值变为 number 类型
<input type="number" v-model.number="age"> {{typeof age}} data: { age: '' }
-
修饰符 trim
作用:自动去除输入框的首尾所有空格
<input type="text" v-model.trim="name"> 您输入的名字是:{{name}} data: { name: '' }
*
4. Vue 组件化开发
4.1. 组件的基本使用
-
Vue.extend() 这种方式几乎现在在 Vue.2x 看不到了 , 这为后面学习打下基础
<my-cpn></my-cpn> 使用组件 <script> // 创建组件构造器对象 const cpnC = Vue.extend({ template: ` <div> <h2>我是标题</h2> <p>我是内容</p> </div>` }) // 注册组件(全局注册)可以在多个 vue 实例中使用 Vue.component('my-cpn', cpnC) </script>
-
局部组件 只在注册的 vue 实例中的范围有效(挂载对象内)
<div id="app"> <cpn></cpn> 有效 </div> <div id="app1"> <cpn></cpn> 无效 </div> <script> // 创建组件构造器对象 const cpn = Vue.extend({ template: ` <div> <h2>我是局部组件标题</h2> <p>我是局部组件内容</p> </div>` }) const app = new Vue({ el: '#app', components: { // 注册组件 cpn // 当上面的名称与使用时的名称相同时, 可以只写一个 } }) const app2 = new Vue({ el: '#app1' }) </script>
4.2. 注册组件语法糖
-
全局
<cpn1></cpn1> 使用 <script> // 推荐语法糖的写法(全局组件) Vue.component('cpn1', { template: ` <div> <h2>我是语法糖标题</h2> <p>我是语法糖内容</p> </div>` }) </script>
-
局部
<cpn2></cpn2> 使用 <script> components: { 'cpn2': { // 注册局部组件语法糖 template: ` <div> <h2>我是局部语法糖标题</h2> <p>我是局部语法糖内容</p> </div>` } } </script>
4.3. 组件模板抽离写法
-
script 标签 注:type=“text/x-template” id 的名称是下面 template 键的值
<cpn3></cpn3> // 在 html 中使用 <script type="text/x-template" id="cpn"></script> <div> <h2>x-template 模板中的标题</h2> <p>x-template 模板中的p</p> </div> <script> <script> 全局注册 Vue.component('cpn3', { template: '#cpn' }) <script>
-
template 标签 id 的名称是下面 template 键的值
<cpn4></cpn4> // 在 html 中使用 <template id="cpn"> <div> <h2>template模板中的标题</h2> <p>template模板中的p1</p> {{test}} </div> </template> <script> 全局注册 Vue.component('cpn4', { template: '#cpn', data() { // 组件中的 data 是一个函数 return { test: '测试通过' } } }) </script>
*
5. 父组件与子组件的通信
5.1. 父传子 props
-
props 的基本用法
<div id="app"> 传值 *注:要使用动态绑定(v-band/:):父组件中 props 中的属性 = "父组件中的数据(需要传的值)" <cpn1 :cmovies="movies" :cmessage="message"></cpn1> /* <cpn1 :movies="movies" :message="message"></cpn1> */ </div> <template id="cpn"> <div> <p><li v-for="item in cmovies">{{item}}</li></p> <p>{{cmessage}}</p> </div> /* <div> <p><li v-for="item in cmovies">{{item}}</li></p> <p>{{message}}</p> </div> */ </template> const cpn = { template: '#cpn', props: ['cmovies', 'cmessage'] 接收父组件传来的数据 /* props: ['movies', 'message'] 接收父组件传来的数据 */ } const app = new Vue({ // 父组件 el: '#app', data: { message: '你好', movies: ['海王', '海贼王', '海尔兄弟'] }, components: { cpn1: cpn } })
-
props 指定传参的 类型 和 提供 默认值 以及 必传值(对传入的数据进行类型限制)
props: { // cmovies: Array, // cmessage: String // 指定一些默认值(没有传递数据的时候有效) cmessage: { type: String, default: 'hello' } cmovies: { type: String, default: 'movie', required: true // 必须传递该数据 否则会报错 } } // 有多种可能的类型 props: { message: [String, Number] } // 也可自定义类型 props: { author: Person // 类 }
-
父访问子-children-refs refs(对象类型) 最常用 children 用的更少
<div id="app"> <cpn ref="aaa"></cpn> <button @click="btnClick">按钮</button> </div> <template id="cpn"> <div>我是子组件</div> </template> <script> const app = new Vue({ el: '#app', methods: { btnClick() { // 通过 this.children 拿到子组件 返回的是一个数组 this.$children[0].showMessage() // 调用子组件中的 showMessage() 方法 // 访问子组件中的 data 中的 name 属性 console.log(this.$children[0].name) // 打印 ref console.log(this.$refs) // 前面的 <cpn ref="aaa"></cpn> console.log(this.$refs.aaa) } }, components: { cpn: { template: '#cpn', methods: { showMessage() { console.log('急急急') } }, data() { return { name: '张三' } } } } }) </script>
5.2. 子传父(自定义事件)
-
通过 事件触发的方式进行子组件传数据给父组件
<body> <div id="app"> <!-- item-click 是触发时的那个名称 cpnClick 在父组件中的 methods 中使用 --> <cpn @item-click="cpnClick"></cpn> </div> </body> <template id="cpn"> <div> <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button> </div> </template> <script> const cpn = { template: '#cpn', methods: { btnClick(item) { // this.$emit('事件的名称', 传递的数据) 自定义事件 // 触发 item-click 事件 在父组件中通过 @item-click="cpnClick" 来触发 this.$emit('item-click', item) // item 是传递的数据 } }, data() { return { categories: [{ id: '1', name: '热门推荐' }, { id: '2', name: '手机数码' } } } } // 父组件模板 const app = new Vue({ el: '#app', methods: { cpnClick(item) { console.log(item) } } components: { cpn } }) </script>
-
子组件访问父组件 parent-root (用的很少)
<div id="app"> <cpn></cpn> </div> <template id="cpn"> <div> <div>我是子组件</div> <button @click="btnClick">按钮</button> </div> </template> <script> const app = new Vue({ el: '#app', data: { name: 'tom' }, methods: { show() { console.log('hello') } }, components: { cpn: { template: '#cpn', methods: { btnClick() { // 使用 this.$parent 的方式访问父组件 console.log(this.$parent.name) // 使用 this.$root 的方式访问父组件中的 show() 方法 this.$root.show() } } } } }) </script>
*
6. slot 插槽
-
插槽的基本使用
<cpn><p>hello 这里是插槽</p></cpn> <template id="cpn"> <div> <h2>我是子组件</h2> <slot></slot> </div> </template> <script> const app = new Vue({ el: '#app', components: { cpn: { template: '#cpn' } } }) </script>
-
slot-具名插槽的使用
- 给插槽取名字
<!-- 左边 中间 右边 替换无名字的 --> <!-- 当没有 name 值的时候会替换 --> <cpn><span>替换无名字的</span></cpn> <!-- 左边 <按钮> 右边 无名字 --> <!-- slot 属性会去找对应 name 的值的那个插槽 --> <cpn><button slot="center">按钮</button></cpn> <template id="cpn"> <div> <slot name="left"><span>左边</span></slot> <slot name="center"><span>中间</span></slot> <slot name="right"><span>右边</span></slot> <slot>无名字</slot> </div> </template> <script> const app = new Vue({ el: '#app', components: { cpn: { template: '#cpn' } } }) </script>
-
作用域插槽使用
- 可以将子组件中的数据在 slot 中使用 (自定义摆放方式)
<div id="app"> <!-- 不使用插槽, 使用默认的插槽 --> <cpn></cpn> <!-- 通过 slot-scope='slot' 拿到模板中的 <slot :data="pLanguage"> --> <cpn> <!-- 目的是获取子组件中的Planguages --> <template slot-scope="slot"> <span v-for="item in slot.data">{{item}} - </span> </template> </cpn> <!-- 通过 v-slot='slot' 拿到模板中的 <slot :data="pLanguage"> --> <cpn> <template v-slot="slot"> <span v-for="item in slot.data">{{item}} * </span> </template> </cpn> </div> <template id="cpn"> <div> <!-- 使用 :data='pLanguage' 使用该插槽的 可以通过 slot.data 来取到 --> <slot :data="pLanguage"> <span v-for="item in pLanguage">{{item}} </span> </slot> </div> </template> <script> const qpp = new Vue({ el: '#app', components: { cpn: { template: '#cpn', data() { return { pLanguage: ['Javascript', 'C++', 'Java', 'PHP', 'Python', 'Go'] } }, } } }) </script>