Vue3 应用

前言:一定要注意这套笔记使用的Vue3,许多Vue2的技术在Vue3中已经被淘汰了。故使用Vue2的小伙伴一定不可生搬硬套。
Vue3是2020年09月18日正式发布的,现在许多Vue的教程都是基于Vue2来讲解的。但是Vue3到Vue2版本之间存在较大差异,博主也是一个刚入门Vue的小白,推荐大家想要快速上手Vue的话,可以先去看以下菜鸟的Vue教程(Vue2与Vue3都有)菜鸟教程 Vue3,视频可以去看b站ilovecoding的 Vue入门到精通,讲的Vue2的实战,主要目的是了解Vue的应用。我们也可以使用Vue3的技术,当然语法可能会不同,可以自行查看官方的文档,或查看上面推荐的菜鸟教程。

Vue的概述
Vue是一套用于构建用户界面的渐进式框架。渐进式的指的是主张最少。每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。
本文不是在去讲Vue的基础语法及应用,基础的东西在Vue官网已经讲的很通俗易懂,故这里只记录Vue在平常项目中的应用与技巧。

1、理解Vue中的MVVM是什么

  • View层:视图层,在我们前端开发中,通常就是DOM层。主要的作用是给用户展示各种信息。
  • Model层:数据层,数据可能是固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。
  • VueModel层:视图模型层,视图模型层是View和Model沟通的桥梁。一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中,也就是我们常说的响应式。另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击,滚动,touch等)时,可以监听到,并在需要的情况下改变对应的Data。

2、表单元素的绑定

以下是官方的原话:
你可以用 v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
text 和 textarea 元素使用 value property 和 input 事件;
checkbox 和 radio 使用 checked property 和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。

一、表单元素绑定与值绑定的综合案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="v-model-radiobutton">
    <h2>文本框 Text</h2>
    <input v-model="text" placeholder="edit me" />
    <p>Text is: {{ text }}</p>

    <h2>多行文本 Textarea</h2>
    <p style="white-space: pre-line;">textarea is:{{ textarea }}</p>
    <br />
    <textarea v-model="textarea" placeholder="add multiple lines"></textarea>

    <h2>复选框 Checkbox</h2>
    <input type="checkbox" id="checkbox" v-model="checked" true-value="yes" false-value="no"/>
    <p>Checked: {{ checked }}</p>

    <h2>单选框 Radio</h2>
    <input type="radio" id="one" value="One" v-model="picked" />
    <label for="one">One</label>
    <br />
    <input type="radio" id="two" value="Two" v-model="picked" />
    <label for="two">Two</label>
    <br />
    <span>Picked: {{ picked }}</span>

    <h2>选择框 Select</h2>
    <div id="v-model-select" class="demo">
        <select v-model="selected">
            <option disabled value="">Please select one</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
        <p>Selected: {{ selected }}</p>
    </div>

</div>
</body>
<script>
    Vue.createApp({
        data() {
            return {
                text:'文本',
                textarea:'文本域',
                checked:'yes',
                picked:'',//没有默认值
                // picked: 'One,'//默认值为One
                selected:'A'
            }
        }
    }).mount('#v-model-radiobutton')
</script>
</html>

二、使用修饰符(限定词)
.lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组织文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步。

<input v-model.lazy="msg" />

.number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

<input v-model.number="age" type="text" />

当输入类型为 text 时这通常很有用。如果输入类型是 number,Vue 能够自动将原始字符串转换为数字,无需为 v-model 添加 .number 修饰符。如果这个值无法被 parseFloat() 解析,则返回原始的值。

.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

<input v-model.trim="msg" />

以上可见 官方文档

3、组件化开发

组件化是Vue.js中的重要思想,它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。任何的应用都会被抽象成一颗组件树。
如果我们将一个页面中的所有逻辑放在一起,处理起来会变得非常复杂,而且不利于后续的管理以及扩展。但如果,我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。

案例1:创建一个绑定Vue实例的组件

<div id="app">
    <my-cpn></my-cpn>
</div>
<script>
    const vm = Vue.createApp({
        data(){
            return{
                message:'gjkhkjh'
            }
        }
    });
    //全局组件,
    vm.component('my-cpn',{
        template:`<div>
            {{a}}
            </div>`,
        data(){
            return{
                a:'自定义组件属性'
            }
        }
    });
    vm.mount('#app');
</script>

案例2:使用JavaScript对象自定义组件(更加灵活)

<div id="app">
    <component-a></component-a>
    <component-b></component-b>
</div>

<script>
    var A = {
        template: '<h1>自定义组件A!</h1>'
    }

    var B = {
        template: '<h1>自定义组件B!</h1>'
    }


    const app = Vue.createApp({
        components: {
            'component-a': A,
            'component-b': B
        }
    }).mount('#app')
</script>

组件模板分离的写法

<div id="app">
    <component-c></component-c>
</div>

<template id="cpn">
    <h2>我是组件分离模板</h2>
</template>

<script>
    const app = Vue.createApp({
        components: {
            'component-c': {
                template:`#cpn`
            }
        }
    })
    app.mount('#app')
</script>

4、组件之间的传值与访问方式

(1)父组件传递数据到子组件(父 =[data]=> 子)#
(2)子组件传递数据给父组件(子 =[data]=> 父)#
(3)父组件的访问子组件 #
(4)子组件的访问父组件(了解即可) #
(5)子父组件之间的双向绑定(了解即可)#

父组件传递数据到子组件
父向子组件传递数据是需要通过props属性传值。

<div id="app">
<component-a :cmovies="movies"></component-a>
</div>

<template id="componentA">
    <ul>
        <li v-for="m in cmovies">{{m}}</li>
    </ul>
</template>

<script>
    var componentA = {
        template: `#componentA`,
        // props:['cmovies'],
        props: {
            cmovies:Array, //要求cmovies属性必须是一个Array类型
            message:{
                type:String,
                default:'aaaaa' //提供默认值
            },
            message2:{//类型是对象或数组时,默认值必须是一个函数
                type:Array,
                default(){
                    return [];
                }
            },
            //自定义验证函数
            propF:{//这个值必须匹配下列字符串中的一个
                validator:function(value){
                    return ['success','warning','danger']
                }
            }
        },
        data(){
            return{

            }
        }
    }


    const app = Vue.createApp({
        data(){
            return{
                movies:['海尔兄弟','海王','海贼王']
            }
        },
        components: {
            'component-a': componentA,//注意组件名不能使用大写字符
        }
    }).mount('#app')
</script>

子组件传递数据给父组件
子组件要将数据传递给父组件要用到$emit方法,它的语法格式为$emit(‘发射事件名称’,[参数])。

<div id="app">
    <cpn @item-click="cpnClick"></cpn>
</div>

<template id="cpn">
    <button v-for="item in categories" @click="$emit('item-click',item)">{{item.name}}</button>
<!--    <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>-->
</template>

<script>
    let cpn = {
        emits:['item-click'],
        template:`#cpn`,
        data(){
            return {
                categories:[
                    {id:'aa',name:'热门推荐'},
                    {id:'bb',name:'手机数码'},
                    {id:'cc',name:'家用家电'},
                    {id:'dd',name:'电脑办公'}
                ]
            }
        },
        methods:{
            // btnClick(item){
            //     this.$emit('item-click',item);
            // }
        }
    }

    let vm = Vue.createApp({
        data(){
            return{

            }
        },
        components:{
            cpn
        },
        methods:{
            cpnClick(item){
                console.log(item);
            }
        }
    }).mount('#app');
</script>

父组件的访问子组件
父组件要访问子组件的数据要使用两个全局对象$children $refs,$children用于取所有的子组件,$refs取ref=’'的子组件。因为在开发中几乎都是使用$refs的方式访问子组件,$children在Vue3中被弃用了。
$refs用法如下:

<div id="app">
    <cpn ref="aaa"></cpn>
    <button @click="btnClick">按钮</button>
</div>

<template id="cpn">
    <h2>子组件</h2>
</template>

<script>
    let cpn = {
        template:`#cpn`,
        methods:{
            showRef(){
                console.log('引用方法')
            }
        }
    }
    let vm = Vue.createApp({
        data(){
            return{

            }
        },
        methods:{
            btnClick(){
                this.$refs.aaa.showRef()
		    }
        },
        components:{
            cpn
        }
    }).mount('#app')
</script>

子组件访问父组件
子组件访问父组件使用$parent对象,但在我们的开发中基本不会这样用。

<div id="app">
    <cpn></cpn>
</div>

<template id="cpn">
    <div>
        <h2>c组件</h2>
        <ccpn></ccpn>
    </div>
</template>

<template id="ccpn">
    <h2>cc组件</h2>
    <button @click="btnClick">按钮</button>
</template>

<script>
    let ccpn = {
        template:`#ccpn`,
        methods:{
            btnClick(){
                console.log(this.$parent.name)
                console.log(this.$root)
            }
        }
    }

    let cpn = {
        template:`#cpn`,
        data(){
            return{
                name:'c组件'
            }
        },
        components:{
            ccpn
        }
    }
    let vm = Vue.createApp({
        data(){
            return{

            }
        },
        methods:{

        },
        components:{
            cpn
        }
    }).mount('#app')
</script>

子组件与父组件的双向绑定

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
    <cpn :cpropsnum1="num1" :cpropsnum2="num2" @pnum1change="num1change" @pnum2change="num2change" />
</div>
</body>
<template id="cpn">
    num1 <br>
    props值: {{cpropsnum1}}<br>
    data值:{{cnum1}}<br>
    <input type="text" v-model="cnum1" @input="cnum1change"><br><br>

    num2 <br>
    props:{{cpropsnum2}}<br>
    data:{{cnum2}}<br>
    <input type="text" v-model="cnum2" @input="cnum2change">
</template>
<script>
    let cpn = {
        emits:['pnum1change','pnum2change'],
        template:`#cpn`,
        props:{
          cpropsnum1:Number,
          cpropsnum2:Number
        },
        data(){
            return{
                cnum1:this.cpropsnum1,
                cnum2:this.cpropsnum2
            }
        },
        methods:{
            cnum1change(event){
                this.cnum1 = event.target.value;
                this.$emit('pnum1change',this.cnum1);
            },
            cnum2change(event){
                this.cnum2 = event.target.value;
                this.$emit('pnum2change',this.cnum2);
            }
        }
    }

    let vm = Vue.createApp({
        data(){
            return{
                num1:1,
                num2:2
            }
        },
        methods:{
            num1change(num1){
                this.num1 = parseFloat(num1);
            },
            num2change(num2){
                this.num2 = parseFloat(num2);
            }
        },
        components:{
            cpn
        }
    }).mount('#app')
</script>
</html>

5、插槽的应用

看一下官方的原话:Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。
<slot>元素主要用于分发内容的接口,它可以有自己的内部实现,也可以由父组件自定义实现来覆盖其内部实现。
下面是插槽的两种使用方式:
1、具名插槽的基本使用

<div id="app">
    <!--slot插槽-->
    <cpn><div>插槽值</div></cpn>

    <!--slot具名插槽-->
    <!--注意,v-slot 只能添加在 <template> 上 (只有一种例外情况)。-->
    <cpn>
        <template v-slot:header>
            <h1>Here might be a page title</h1>
        </template>

        <template v-slot:default>
            <p>A paragraph for the main content.</p>
            <p>And another one.</p>
        </template>

        <template v-slot:footer>
            <p>Here's some contact info</p>
        </template>
    </cpn>
</div>
<template id="cpn">
    <!--普通插槽-->
<!--    <slot>-->
<!--        <div>插槽的默认值</div>-->
<!--    </slot>-->
    <!--具名插槽-->
    <div class="container">
        <header>
            <slot name="header"></slot>
        </header>
        <main>
            <slot></slot>
        </main>
        <footer>
            <slot name="footer"></slot>
        </footer>
    </div>
</template>
<script>
    let cpn = {
        template:`#cpn`,
        methods:{

        }
    }
    let vm = Vue.createApp({
        data(){
            return{

            }
        },
        methods:{

        },
        components:{
            cpn
        }
    }).mount('#app')
</script>

2、自定义组件的渲染方式

<div id="app">
    <h2>使用子组件的默认渲染方式(slot的默认值)</h2>
    <cpn></cpn>
    <h2>父组件自定义子组件的渲染方式</h2>
    <cpn>
        <!--slotProps为自定义名称,它是一个封装了slot属性的Object-->
        <template v-slot:myslot="slotProps">
            <span>{{slotProps.data.join(" >>> ")}}</span>
        </template>
    </cpn>
</div>
<template id="cpn">
    <div>
        <slot name="myslot" :data="planguage"> <!--data为自定义属性名-->
            <ul>
                <li v-for="item in planguage">{{item}}</li>
            </ul>
        </slot>
    </div>
</template>

<script>
    let cpn = {
        template:`#cpn`,
        data(){
            return{
                planguage:['Java','C++','C#','Go','Javascript']
            }
        },
        methods:{

        }
    }
    let vm = Vue.createApp({
        data(){
            return{
                message:'你哈'
            }
        },
        methods:{

        },
        components:{
            cpn
        }
    }).mount('#app')
</script>

6、Vue中有哪些响应式操作数组的方法

在Vue的实例中操作Data Model中的数组,且View视图模型也会跟着改变,即要做到数组的响应式操作有哪些方法。例如下面对数组的某个下标直接赋值的操作,数据改变了,但是前端展示的数据是不会变的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
    <ul>
        <template v-for="item in hobby">
            <li>{{item}}</li>
        </template>
    </ul>
    <button v-on:click="btnClick">按钮</button>
</div>
</body>
<script>
    let vm = Vue.createApp({
        data(){
            return{
                hobby:['a','b','c','d']
            }
        },
        methods:{
            btnClick(){
                this.hobby[0] = 'aaaaa';
                console.log(this.hobby);
            }
        }
    }).mount('#app')
</script>
</html>

那么在Vue中有哪些实用的操作数组响应式的方法呢

方法描述
push()在数组后面添加新元素
pop()删除数组中的最后一个元素
shift()删除数组中的第一个元素
unshift()在数组最前面添加新元素
splice()可用于删除、插入、替换数组元素
sort()给数组排序
reverse()数组元素反转

我们来用用看

let vm = Vue.createApp({
    data(){
        return{
            hobby:['a','b','c','d']
        }
    },
    methods:{
        btnClick(){
            // 1.push:在数组最后面添加元素
            this.hobby.push('aaa');
        }
    }
}).mount('#app');

splice()方法使用详解
格式:splice(起始元素下标, [删除元素个数],[替换元素...])
splice(0,1);删除下标0开始往后1个元素
splice(0,1,‘a’);将下标为0的元素替换为a。(实际上是先删除了下标0的元素,再将a插入)
splice(index,0,‘a’,‘b’,‘c’);将a,b,c插入到下标为index的元素前面
splice(index+1,0’a’;‘b’,‘c’)将a,b,c插入到下标为index的元素后面

注意:以上响应式的问题在Vue3中实际上已经得到了解决。

7、Vue3的组合式API

1、setup函数,setup 选项在组件创建之前执行,一旦 props 被解析,就将作为组合式 API 的入口。

export default {
  name: 'App',
  setup(){
    const name = ref('马云');
    function f1() {
      this.name = '马化腾';
    }
  }

2、ref函数,在 Vue 3.0 中,我们可以通过一个新的 ref 函数使任何响应式变量在任何地方起作用,如下所示:

import {ref} from 'vue'
export default {
  name: 'App',
  setup(){
    const name = ref('马云');
    function f1() {
      this.name = '马化腾';
    }
    return {name,f1};
  }
}

Vue案例

购物车

购物车

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue@next"></script>
    <style>
        table{
            border-collapse: collapse;
            width: 100%;
            text-align: center;
        }
    </style>
</head>
<body>
    <div id="app">
        <fieldset>
            <legend>商店</legend>
            <table border="1" cellspacing="0" cellpadding="5">
                <thead>
                    <tr>
                        <th>序号</th>
                        <th>书籍名称</th>
                        <th>出版日期</th>
                        <th>购买数量</th>
                        <th>价格</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                <template v-for="(v,k) in books">
                    <tr>
                        <td>{{k}}</td>
                        <td>{{v.name}}</td>
                        <td>{{v.publishDate}}</td>
                        <td>¥{{v.price.toFixed(2)}}</td>
                        <td>
                            <button @click="reduce(k)" :disabled="v.count<=1">-</button>
                            {{v.count}}
                            <button @click="increment(k)">+</button>
                        </td>
                        <td>
                            <button @click="removeBooks(k)">删除</button>
                        </td>
                    </tr>
                </template>
                </tbody>
            </table>
            <h2 v-show="books.length>0">总价{{getTotal}}</h2>
            <h2 v-show="books.length<=0">购物车为空</h2>
        </fieldset>
    </div>
</body>
<script src="../js/cart.js"></script>
</html>

js文件

let vm = Vue.createApp({
    data(){
        return{
            books:[
                {
                    name:'《算法导论》',
                    publishDate:'2006-9',
                    price: 85.00,
                    count:1
                },
                {
                    name:'《UNIX编程艺术》',
                    publishDate:'2006-2',
                    price: 59.00,
                    count:1
                },
                {
                    name:'《编程珠玑》',
                    publishDate:'2008-9',
                    price: 39.00,
                    count:1
                },
                {
                    name:'《代码大全》',
                    publishDate:'2006-3',
                    price: 128.00,
                    count:1
                }
            ]
        }
    },
    methods:{
        increment(index){
            this.books[index].count++;
        },
        reduce(index){
            this.books[index].count--;
        },
        removeBooks(index){
            this.books.splice(index,1);
        }
    },
    computed:{
        getTotal(){
            let total = 0;
            for (let i = 0; i < this.books.length; i++) {
                total +=this.books[i].count * this.books[i].price;
            }
            return '¥' + total.toFixed(2);
        }
    }
})
vm.mount('#app')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值