初学 Vue

* 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>
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值