vue入门--js高阶函数(箭头函数)、v-model数据绑定、组件化、父子组件通信及访问

vue入门–基础命令+axios+案例练习
vue入门–vue常用属性、生命周期、计算属性、过滤器、组件、虚拟DOM、数组的响应式方法、页面闪烁、ES6简单语法增强
vue入门–js高阶函数(箭头函数)、v-model数据绑定、组件化、父子组件通信及访问
vue入门–插槽(具名、匿名、作用域插槽)+ES6模块化导入导出+webpack的使用(基本使用+配置使用+如何一步步演化成cli脚手架)+webpack插件使用(搭建本地服务器、配置文件分离)
vue-cli脚手架2版本及3+版本安装、目录解析、only和compiler的区别、3+版本如何改配置、箭头函数及this的指向
vue-router基本使用、路由传参、懒加载、嵌套路由、导航守卫、keep-alive
Promise基本使用、三种状态、链式调用及简写、all方法
Vuex的作用、使用、核心概念(State、Mutations、Getters、Actions、Modules)、文件抽离
axios网络请求基本使用、配置使用(全局axios和局部axios实例)、模块封装、axios拦截器

JavaScript高阶函数

在说javascript高阶函数之前,有这样一个案例,有一个对象数组,我要计算数组中所有对象的总金额问题。

let books = [{
    
    
                id: 1,
                name: "《算法导论》",
                date: "2006-9",
                price: 85.12,
                count: 2
            },
            {
    
    
                id: 2,
                name: "《UNIX编程艺术》",
                date: "2006-2",
                price: 59.28,
                count: 1
            },
            {
    
    
                id: 3,
                name: "《编程珠玑》",
                date: "2008-10",
                price: 39.2,
                count: 1
            }
        ]

普通方法: 普通for循环/for in /for of

let total=0
// 普通for循环
for (let i = 0; i < books.length; i++) {
    
    	
    total += books[i].count*books[i].price;
}
return total;
--------------------------------------------------------------------------
// for in  实际上和 普通for循环一样
for (let i in books) {
    
    	// i 是下标
    total += books[i].count*books[i].price;
}
return total;
--------------------------------------------------------------------------
// for of  一般循环遍历,尽量优先使用 for of
for (const book of books) {
    
    	// i 是元素
    total += book.count*book.price;
}
return total;

每次计算都需要循环遍历,代码写起来很麻烦,有没有一种函数,直接给我把值全都计算好呢。当然有,和java stream的reduce规约操作一样,js一样有reduce规约操作。

reduce–高阶函数之规约操作

语法:

reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number)

可以看到,这个方法中需要两个参数:

  • 回调函数(必填)

    • previousValue(必填):上一次计算的结果值(注意:当没有设置初始值时,第一次执行时,数组中的第一个元素将会作为计算结果)
    • currentValue(必填):当前元素
    • 非必填的可以去查阅详细资料
  • 初始值(非必填)

    一般情况下是不需要设置初始值的,但是如果是对象类型的数组,你会发现这个初始值设计的巧妙。

普通数组

先看下普通的数组,求数组中所有数据之和,因为是普通值类型数组,一般情况下只传入一个回调函数就完全够用,previousValue会被当成初始值;如果有初始值要求设置上就行了

普通回调函数

let arrs = [10, 20, 30, 111, 500,34]
function arrsReduce(){
    
    
    return arrs.reduce(function(preValue, n){
    
    
        return preValue + n;
    })
}

箭头函数回调

let arrs = [10, 20, 30, 111, 500,34]
function arrsReduce(){
    
    
    return arrs.reduce((preValue, n) => preValue + n);
}

对象数组

还使用上面说到的计算数组中所有对象的总金额问题。

箭头函数回调

function finalTotal(){
    
    
    return books.reduce((preValue, n) => prevalue + n.count*n.price, 0);
}

会发现,上面用遍历写了一大堆,结果这边用一个规约操作,直接一行代码全搞定。

当对对象数组进行规约操作计算某总值时,一定要注意preValuen分别代表什么,如上preValue是上一次计算出的总额,那么preValue必须是number类型的。而n是一个对象类型,一定要知道。

那么刚开始执行时,preValue不能是第一个元素,只能是初始值0。

filter–高阶函数之过滤操作

filter回调函数中有一个要求:必须要返回一个boolean值

返回true时,函数内部会将这次回调的参数加入到新的数组中,false则被过滤掉

普通回调函数

let arrs = [10, 20, 30, 111, 500,34]
function arrFilter(){
    
    
    return arrs.filter(function(n){
    
    	// 每次遍历将数组中的元素一个个赋值给 n
        return n > 100	// 当返回值为 true,会把当前的n加入到新的数组中
    });
}

箭头函数回调

不明白箭头函数的可以查下资料学习下,这里简单复习下

当函数中参数只有一个时,()可以省略不写;当函数体内语句只有一句时 {} 可以不写,并且return也可以不写。

let arrs = [10, 20, 30, 111, 500,34]
function arrFilter(){
    
    
    return arrs.filter(x => x > 100);
}

map–高阶函数之映射操作

可单独对数组中每个元素进行操作,比如每个元素都 *2等,最后会生成新的数组

普通函数回调

let arrs = [10, 20, 30, 111, 500,34]
function arrMap(){
    
    
    return arrs.map(function(n){
    
    
        return n * 2
    });
}

箭头函数回调

let arrs = [10, 20, 30, 111, 500,34]
function arrMap(){
    
    
    return arrs.map(n => n*2);
}

v-model

text

双向绑定,数据和视图的绑定

<div id="app">
    <input type="text" v-model="message">
    {
   
   {message}}
</div>
<script>
    const app = new Vue({
      
      
        el:"#app",
        data:{
      
      
            message:"你好"
        }
    })
</script>

radio

使用v-model绑定同一个属性后,name可以省略(分组)

<div id="app">
    <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>
    {
   
   {sex}}
</div>
<script src="./vue/vue.js"></script>
<script>
    const app = new Vue({
      
      
        el:"#app",
        data:{
      
      
            sex: '女'
        }
    })
</script>

checkbox

<div id="app">
    <!-- 单选框 -->
    <label for="agree">
        <input type="checkbox" id="agree" v-model="isAgree">同意
    </label>
    <h2>你选择的是{
   
   {isAgree}}</h2>
    <button :disabled="!isAgree">下一步</button>

    <!-- 多选框 -->
    <input type="checkbox" value="篮球" v-model="hobby">篮球
    <input type="checkbox" value="足球" v-model="hobby">足球
    <input type="checkbox" value="乒乓球" v-model="hobby">乒乓球
    <h2>您的爱好是{
   
   {hobby}}</h2>

</div>
<script src="./vue/vue.js"></script>
<script>
    const app = new Vue({
      
      
        el:"#app",
        data:{
      
      
            isAgree: false,
            hobby: []
        }
    })
</script>

select

<div id="app">
    <select name="abc" id="" v-model="fruit">
        <option value="苹果">苹果</option>
        <option value="香蕉">香蕉</option>
        <option value="橘子">橘子</option>
    </select>
    <h2>{
   
   {fruit}}</h2>

    <select name="abc"  v-model="fruits" multiple>
        <option value="苹果">苹果</option>
        <option value="香蕉">香蕉</option>
        <option value="橘子">橘子</option>
    </select>
    <h2>{
   
   {fruits}}</h2>
</div>
<script src="./vue/vue.js"></script>
<script>
    const app = new Vue({
      
      
        el:"#app",
        data:{
      
      
            fruit: '香蕉',
            fruits: []
        }
    })
</script>

在这里插入图片描述

修饰符

  • .lazy : 绑定的属性懒加载,只有失去焦点或者用户输入回车时才去加载
  • .number : 表示绑定的值是number类型
  • .trim : 自动去除两端空格

组件化

就是将一个大的整体,拆分成一个个的小整体的组件。

基本使用

<div id="app">
    <my-cpn></my-cpn>	// 调用组件
</div>
<script src="./vue/vue.js"></script>
<script>
    Vue.component('my-cpn', {
      
      	// params1: 组件名称
        template: `				// params2: 定义模板
			<div>
				<h2>标题</h2>
		    </div>`
    })
    const app = new Vue({
      
      
        el:"#app"
    })
</script>

全局组件和局部组件


// 此写法为全局组件,其他的vue对象中,也可以使用
Vue.component('my-cpn', {
    
    
    template: `
<div>
<h2>标题</h2>
</div>`
})
const app = new Vue({
    
    
    el:"#app"
})

-------------------------------------------------------
// 此写法为局部组件,只有在一个vue实例中,可以使用
const app = new Vue({
    
    
    el:"#app",
    components:{
    
    
        cpn:{
    
    	// 	组件名是 cpn
            template: `
                <div>
                <h2>标题</h2>
                </div>`
        }
    }
})

组件模板抽离写法

<div id="app">
    <cpn></cpn>		<!-- 使用模板 -->
</div>
<template id="cpn">		<!-- 定义模板 -->
    <h2>标题</h2>
</template>
<script src="./vue/vue.js"></script>
<script>
    const app = new Vue({
      
      
        el:"#app",
        components:{
      
      
            cpn:{
      
      
                template: "#cpn"	// 将模板和组件绑定起来
            }
        }
    })
</script>

请注意:template标签中必须有且只有一个root级的标签,否则会报错。

以上 <template></template>中只写了一句<h2></h2>,如果有多个元素,请一定要使用 <div></div>或其他元素将它们包裹起来,如下:

<template id="cpn">		<!-- 定义模板 -->
	<div>
        <h2>标题</h2>
        <p>内容</p>
    </div>
</template>

组件中的数据存放问题

问题:组件中能否访问vue实例中的数据

组件如果想要访问vue实例中的数据,不能直接去访问,需要通过模板进行参数的传递。同vue实例中的data属性一样,组件也可以有存储数据的地方,但是与vue实例不同的是,组件中的data只能是一个函数,而不能是一个属性

<div id="app">
    <cpn></cpn>
</div>
<template id="cpn">
    <h2>{
   
   {title}}</h2>
</template>
<script src="./vue/vue.js"></script>
<script>
    const app = new Vue({
        el:"#app",
        components:{
            cpn:{
                template: "#cpn",
                
                // 组件中定义一个 data函数,用于返回数据
                data(){
                    return {	// 返回一个数据为对象类型
                        title: "标题"
                    }
                }
            }
        }
    })

问题:为什么组件中的data必须是函数

可以从vue组件的实例化角度考虑,一个vue组件如果实例化多次,那么我们会想多个实例化对象是相互独立,互不影响的,data设置为函数,然后data函数中每次返回一个新的对象。那么vue组件多个实例使用的都不是同一个data的对象,自然就实现了多实例之间数据的互不影响。

父子组件及通信

每个组件中都有 components属性,如果要套子组件,那么直接在组件的 components中继续加组件即可。其实vue实例也可以看成为一个组件。

要注意:父子组件不可以跨级调用,除非在全局组件作用域中。

通信两种方式:

  • props:通过props向子组件传送数据
  • 通过事件向父组件发送消息 $emit

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R5V1BUlt-1652938819225)(imgs/18.png)]

props : 父向子传递数据

props可以是一个数组,也可以是一个对象(可加数据类型验证等等)推荐使用

<div id="app">
    <!-- 将父组件的 movies属性值传给了 子组件的 cmovies属性 -->
    <cpn :cmovies="movies" :cmessage="message"></cpn>	
</div>
<template id="cpn">
    <div>
        <p>{
   
   {cmovies}}</p>
        <h2>{
   
   {cmessage}}</h2>
    </div>
</template>

<script src="./vue/vue.js"></script>
<script>
    const cpn ={
      
      
        template: "#cpn",
        // props:['cmovies', 'cmessage']   // props可以是一个数组,记得加 ''
        props:{
      
      
            cmovies: Array, //可以进行数据类型验证
            cmessage: {
      
           // 可设置对象
                type: String,   // 类型
                default: 'aaa'  // 默认值
            }
        }
    }
    const app = new Vue({
      
      
        el:"#app",
        data:{
      
      
            movies:["海王", "加勒比海盗", "海尔兄弟"],
            message: "hello"
        },
        components:{
      
      
            cpn		// es6增强写法,当k和v同名时,可以省略只写一个
        }
    })
</script>

如果是Object或者Array类型,那么很可能高版本的vue不支持此写法

props:{
    
    
    cmovies:{
    
    
		type: Array,
        default: []
    }
}

提示报错,Invalid default value for prop: .. Props with type Object/Array must use a factory function to return the default value

写法改为:

props:{
    
    
    cmovies: {
    
    
        type: Array,
            default(){
    
    
                return []
            }
    }
}

写法总结图:

在这里插入图片描述

props中驼峰标识

假如我定义的props中有驼峰式写法

props:{
    
    
    cInfo:{
    
    
        type: Object,
            default(){
    
    
                return {
    
    }
            }
    }
}
<cpn :cInfo="info"></cpn>	<!--这里会无法传递给cInfo-->
<cpn :c-info="info"></cpn>	<!--这里能正常传递给cInfo--> 
<!--在html中使用中划线写法,会自动解析为驼峰式写法-->

$emit子组件向父组件发消息(自定义事件)

<div id="app">
    <cpn @cateclick="cpnClick"></cpn>	<!--使用自定义事件,调用了 cpnclick函数,不用写(参数),会											自定将参数传过去-->
</div>
<template id="cpn">
    <div>
        <button v-for="cate in categories" @click="btnClick(cate)">{
   
   {cate.name}}</button>
    </div>
</template>
<script src="./vue/vue.js"></script>
<script>
    const cpn = {
      
      
        template: "#cpn",
        data(){
      
      
            return {
      
      
                categories: [
                    {
      
      id: 'aaa',name: "热门推荐"},
                    {
      
      id: 'bbb',name: "手机数码"},
                    {
      
      id: 'ccc',name: "家用家电"},
                    {
      
      id: 'ddd',name: "电脑办公"}
                ]
            }
        },
        methods:{
      
      
            btnClick(cate){
      
      
                this.$emit("cateclick", cate)   // (自定义一个事件)发送事件,cate是参数
            }
        }
    }
    const app = new Vue({
      
      
        el:"#app",
        components:{
      
      
            cpn
        },
        methods:{
      
      
            cpnClick(cate){
      
      		// 用来接收 子组件传给的参数
                console.log(cate)
            }
        }
    });
</script>

结合v-model实现父子通信

:value + @input实现

首先要知道,v-model的实现其实就是:value绑定和@input传入来完成的

实现需求:

子组件中有一个输入框,需要把输入框中输入和数据及时更新到父组件的属性中,由于子组件中如果v-model来绑定props,vue不支持这种写法,所以我们要绑定子组件中的 data函数中的参数,并且当输入框输入数据后,通过自定义事件将值传递给父组件。

由于涉及到输入(事件)、展示(属性),所以不使用v-model进行绑定,而是使用底层的:value@input来配合完成。一般来讲,这种需求比较难遇到。

<div id="app">
    <cpn :number1="num1" :number2="num2" @num1change="num1change" 		          @num2change="num2change"></cpn>
</div>

<template id="cpn">
    <div>
        num1:<input :value="dnumber1" @input="num1change"/> data:{
   
   {dnumber1}}  props:{
   
   {number1}}<br>
        num2:<input :value="dnumber2" @input="num2change"/> data:{
   
   {dnumber2}}  props:{
   
   {number2}} 
    </div>
</template>

<script src="./vue/vue.js"></script>
<script>
    const cpn = {
      
      
        template:"#cpn",
        props:{
      
      
            number1: Number,
            number2: Number
        },
        data(){
      
      
            return{
      
      
                dnumber1: this.number1,
                dnumber2: this.number2
            }
        },
        methods:{
      
      
            num1change(event){
      
      	// 这里会默认把浏览器的事件传过来
                this.dnumber1 = event.target.value;
                this.$emit('num1change', this.dnumber1)
            },
            num2change(event){
      
      
                this.dnumber2 = event.target.value;
                this.$emit('num2change', this.dnumber2)
            }
        }
    }
    const vue = new Vue({
      
      
        el:"#app",
        data:{
      
      
            num1: 1,
            num2: 2
        },
        components:{
      
      
            cpn
        },
        methods:{
      
      
            num1change(value){
      
      
                this.num1 = parseInt(value)
            },
            num2change(value){
      
      
                this.num2 = parseInt(value)
            }
        }
    })
</script>

watch监听实现

在子组件中定义watch监听

watch:{
    
    
    dnumber1(newValue){
    
    	// 函数名就是 属性名,然后参数是 (新值[,旧值]),旧值非必填
        this.dnumber1 = newValue;
        this.$emit('num1change', this.dnumber1)
    }
}

父访问子&子访问父

  • 父访问子 : $children或者 $refs
  • 子访问父 : $parent

父访问子

父访问子:使用 $children(不推荐使用)

$children是获取到子组件的数组。数组中是所有的子组件,形成一个树形结构。

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

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

<script src="./vue/vue.js"></script>
<script>
    const cpn = {
      
      
        template:"#cpn",
        methods: {
      
      	// 方法
            showMessage(){
      
      	// 子组件中定义方法
                console.log("showMessage")
            }   
        }
    }
    const app = new Vue({
      
      
        el:"#app",
        components:{
      
      
            cpn
        },
        methods: {
      
      
            btnClick(){
      
      
                console.log(this.$children);	// 使用 $children获取所有子组件的集合,然后可以														调用子组件中的属性或者是方法
                this.$children[0].showMessage();	// 调用第一个子组件的 方法
            }   
        }
    })
</script>

在这里插入图片描述

父访问子: 使用 $refs (推荐使用)

直接根据ref能拿到子组件对象,注意是对象,不是集合

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

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

<script src="./vue/vue.js"></script>
<script>
    const cpn = {
      
      
        template:"#cpn",
        methods: {
      
      
            showMessage(){
      
      
                console.log("showMessage")
            }   
        }
    }
    const app = new Vue({
      
      
        el:"#app",
        components:{
      
      
            cpn
        },
        methods: {
      
      
            btnClick(){
      
      
                console.log(this.$refs.aaa);
                this.$refs.aaa.showMessage();
            }   
        }
    })
</script>

子访问父

要注意层级关系,当父组件是 Vue实例的时候,那么父组件的类型就是一个 Vue类型,如果是父组件还是一个组件类型,那么父组件的类型就是 VueComponet。注意:获取到的是对象,不是数组

$parent,不推荐使用

由于会打乱结构,与组件独立这一观念冲突,一般不会去使用 $parent,更多是使用 $root直接获取vue实例对象。($parent就不再演示)

$root,直接获取vue实例

<div id="app">
    <cpn></cpn>
</div>
<template id="cpn">
    <div>
        <h2>我是子组件</h2>
        <button @click="btnClick">按钮</button>
    </div>
</template>
<script src="./vue/vue.js"></script>
<script>
    const cpn = {
      
      
        template:"#cpn",
        methods: {
      
      
            btnClick(){
      
      
                // 访问父组件
                console.log(this.$root);
                console.log(this.$root.message)
            }   
        }
    }
    const app = new Vue({
      
      
        el:"#app",
        data:{
      
      
            message: "你好"
        },
        components:{
      
      
            cpn
        }
    })
</script>
vue入门–基础命令+axios+案例练习
vue入门–vue常用属性、生命周期、计算属性、过滤器、组件、虚拟DOM、数组的响应式方法、页面闪烁、ES6简单语法增强
vue入门–js高阶函数(箭头函数)、v-model数据绑定、组件化、父子组件通信及访问
vue入门–插槽(具名、匿名、作用域插槽)+ES6模块化导入导出+webpack的使用(基本使用+配置使用+如何一步步演化成cli脚手架)+webpack插件使用(搭建本地服务器、配置文件分离)
vue-cli脚手架2版本及3+版本安装、目录解析、only和compiler的区别、3+版本如何改配置、箭头函数及this的指向
vue-router基本使用、路由传参、懒加载、嵌套路由、导航守卫、keep-alive
Promise基本使用、三种状态、链式调用及简写、all方法
Vuex的作用、使用、核心概念(State、Mutations、Getters、Actions、Modules)、文件抽离
axios网络请求基本使用、配置使用(全局axios和局部axios实例)、模块封装、axios拦截器

猜你喜欢

转载自blog.csdn.net/weixin_45248492/article/details/124861486