IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue全家桶(一) -> 正文阅读

[JavaScript知识库]Vue全家桶(一)

今天写了一天的时间,麻烦读者怀一颗感恩的心阅读哈~小编提前感谢大家咯


小编今天为大家推出一期vue全家桶续集~按照下述的xmind来哦,有兴趣的童鞋可以提前预习一下。。。
请添加图片描述

一.vue框架

1.项目的框架模式(MV*)

1.1.MVC架构模式

1.MVC的出现用在后端(全栈时代)。
2.M:model,模型,主要完成业务功能,在数据库相关的项目中,数据的增删改查
V:view,视图,主要负责数据的显示(html+css)。
C:controller,控制器,主要负责每个业务的核心流程,在项目中体现在路由以及中间件上。
在这里插入图片描述
3.优缺点:

  • 优点:
    耦合度低、复用性高、生命周期成本低、部署快、可维护性高、有利于软件工程化管理。
  • 缺点
    由于模型和视图分离,这样给调试应用程序带来困难。

1.2MVP架构模式

1.MVP:Model View Presenter,分别表示数据、视图和发布层。是MVC架构的一种演变。
2.M:model,模型,主要完成业务功能,在数据库相关的项目中,数据的增删改查
V:view,视图,主要负责数据的显示(html+css)。
p:Presenter负责业务流程的逻辑处理,Presenter是从Model中获取数据并提供给View层,Presenter还负责处理后端任务。
在这里插入图片描述
3.MVP模式与MVC模式的区别:
MVP模式中的View不直接使用Model,而MVC模式中View可以绕过Controller,从Model中直接读取数据。

1.3MVVM架构模式

1.MVVM是Model-View-ViewModel,MVVM模式与MVP模式相似。唯一区别是MVVM模式采用的是数据双向绑定
在这里插入图片描述

1.4总结

1.vue采用的是MVVM模式,M-V-VM,M是数据,V是视图,VM负责M与V相互通信。
2.架构是一种思维方式,是一种思考问题解决问题的思维。目的解决编程过程中模块内部高内聚、模块与模块直接的低耦合、可维护性、易测试等。
3.架构有利于做好代码的分工,配合

二.vue框架的核心

1.vue框架的核心:数据驱动和组件化。

  • 数据驱动:数据的变化驱动页面发生变化,不用操作DOM。(一定要切记幺,是不是有的宝宝一冲动,就想操作Dom啦)
  • 组件化:把页面封装成若干个组件,把组件进行拼装,让页面的复用性达到最高。

三.初识vue框架(vue官网)

温馨提示?:要多看官方API,英语基础弱的小伙伴,可以直接看代码示例,直接上代码~

铺垫:
1.vue的作者:尤雨溪(华人),前Google员工;
2.vue是构建数据驱动的web应用开发框架;
3.vue是一套用于构建用户界面的渐进式框架;(渐进式:可以在原有的系统上开发,把一两个组件改用vue实现,也可以整个用vue全家桶开发,不会做职责之外的事。)
4.vue被设计为可以自顶向上增量开发逐层应用;( 自顶向上增量开发:先写一个基础页面,把基础的东西写好,再逐一添加功能和效果,由简单到繁琐的过程。)
5.vue的核心只关注视图层;
6.vue框架的核心:数据驱动组件化
7.vue不支持IE8及以下版本。

3.1vue框架

3.1.1理解

1.写好HTML模板,声明式地告知vuejs库,数据显示在何处,在vue对象中处理数据,不用做DOM操作(vuejs库会帮我们做哦)即new出来一个Vue实例,传一堆配置参数,就可以控制一片html。
在这里插入图片描述

3.1.2名词解释

  • 数据驱动:通过控制数据的变化来改变(驱动)DOM,背后使用了观察者模式,靠数据的变化来控制页面的变化。
  • 声明式渲染:告知程序(vue框架),在何处渲染什么数据。
  • 数据绑定:是通过数据劫持观察者模式的方式来实现的。
    ①数据劫持:vue2.x使用Object.defineProperty();,vue3使用的是Proxy。把普通JavaScript对象(json)传入Vue实例作为data选项,Vue将遍历此对象所有的属性,并使用Object.defineProperty()把这些属性全部转为getter/setter。
    在这里插入图片描述
class MyVue {
    constructor(obj) {
        // 定义一个属性保存原始的html代码(带着双括号等vue的指令)
        this.sourc`e`HtmlStr = document.querySelector(obj.el).innerHTML;

        // 订阅(Observer)
        // 在html里查找什么地方使用 数据 key
        // 此处本该使用循环,去订阅所有数据的变化
        // 但是,现在算了,只考虑msg的变化。
        let o = new Observer();
        o.addSubsciber((what) => {
            this.render(); //此处只是模拟,
        });

        // 把obj的根属性作为vue对象的属性(属性名前面加上了$)
        for (let key in obj) {
            this["$" + key] = obj[key];
        }

        // 一、数据劫持(把obj里的data里的每个属性,增加setter和getter)。
        for (let key in obj.data) {
            Object.defineProperty(this, key, {
                set: function(newVal) {
                    this["_" + key] = newVal;
                    this.$data[key] = newVal;
                    // 能够感知到当前属性被改了。
                    // console.log(key+"被改了");
                    // 利用观察者模式,进行发布了(修改dom)。
                    o.publish(newVal);
                },
                get: function() {
                    return this["_" + key];
                }
            });
        }

        // 二、渲染
        this.render();
    }

    render() {
        // 操作dom       
        let newHtmlStr = this.sourceHtmlStr;
        for (let key in this.$data) {
            // newHtmlStr = newHtmlStr.replace(/{{msg}}/g,this.$data.msg);
            newHtmlStr = newHtmlStr.replace(new RegExp("{{" + key + "}}", "g"), this.$data[key]);
        }
        document.querySelector(this.$el).innerHTML = newHtmlStr;
    }

}

class Observer {
    constructor() {
            this.arr = [];
        }
        // 添加订阅者
    addSubsciber(cb) {
            this.arr.push(cb);
        }
        // 删除订阅者
    removeSubscriber(cb) {
            let index = this.arr.indexOf(cb);
            this.arr.splice(index, 1);
        }
        // 发布
    publish(what) {
        this.arr.forEach(item => {
            item(what);
        });
    }
}

②观察者模式(发布订阅模式):
目的:当属性发生变化时,所有使用该数据的地方跟着变化。(响应式)

// 发布订阅者模式
let observer = {
    arr:[],//存储的是所有的订阅者
    // 添加订阅者
    addSubscriber:function(fn){
        this.arr.push(fn);
    },
    // 发布:
    publish:function(what){
        this.arr.forEach(fn=>{
            fn(what);
        });
    }
}
  • 组件:页面中的一个个ui部件,写在components文件夹下。
  • 页面组件:项目中的一个个页面整体,写在views/pages文件夹下。
  • 单页面应用(SPA):single page application,整个项目中只有一个HTML页面(文件),首次加载是,把所有的html、css、js全部加载下来。通过操作dom的删除和创建(添加)来完成页面的切换。
  • 单页面文件:single-file components,文件扩展名为 .vue 的 (单文件组件) 。(这点小编还不太清楚,弄懂了及时告诉你们哦~)

四.组件

组件封装的是完整的功能(包括:html、css、js),而函数只封装js(逻辑)。

4.1概念

1.组件是自定义标签,vueJS提供的组件可以让程序员自定义标签,对页面进行模块化。每个标签中包含html、css、js。
2.vue的组件是一个vue对象,vue对象的配置项,在vue组件中可以使用。
注:

  • 没有el属性;
  • template:HTML模板代码,只能有一个根标签;
  • data:必须是个函数;? 组件中的 data 必须是一个函数,且要返回object,只有这样,每个实例(vue组件对象)就可以维护一份被返回对象的独立的拷贝,否则组件复用时,数据相互影响,也就是说,组件的作用域是独立的。
    ? 简单回答:如果不是函数,那么,复用的组件的data共享同一块内存空间。

一个完整的标签名格式: <标签名 属性名=“属性值" 事件=”函数“>内容</标签名>
根据HTML的标签理解组件,我也是根据标签的格式,来说组件啦~

4.2组件的基本使用(标签名)

4.2.1定义组件

(一)标准版

let 组件变量名= Vue.extend({
        template:'<div class="header">{{msg}},我是header组件</div>'
        data:function(){
			return {
				msg:”hi”
			}
		},
  });

(二)简化写法

let 组件变量名={
        配置项
}; 

4.2.2注册组件

  • 全局注册component:在任何vue对象里都可以使用。
Vue.component('组件名',组件变量名);
  • 局部注册components:只能在当前vue对象(组件)里使用。
//在vue对象的components选项里进行注册
new Vue({
     el:
     components:{
    	 组件名:组件变量名
     }     
});

4.2.3使用组件

组件就是自定义标签,使用组件就和使用官方标签是一样的。直接写名称就可以。

注意:如果组件定义时变量为驼峰命名,则在使用时,使用羊肉串的方式。双标签和单标签都可以的吆~
<组件名></组件名>
<组件名/>

4.2.4组件嵌套

把一个组件的标签写在另外一个组件的template中。
eg:父组件中嵌套了子组件

 //子组件 
  let myComSon = {
        template:"<div>我是son里的div:{{msg}}</div>",    
        data:function(){
            return {
                msg:"hi:son"
            }
        }
    };

   //父组件 
    let myComParent = {
        template:`<div>
                        <p>我是p:{{msg}}</p>
                        <my-com-son></my-com-son>                    
                    </div>`,
        data:function(){
            return {
                msg:"hi"
            }
        },
        components:{
            // 局部注册了另外一个组件
            "my-com-son":myComSon
        }    
    };

4.2.5组件编写方式 vs Vue实例的区别

来自小编的福利:小驼峰和大驼峰
小驼峰:除过首字母不大写,其余单词首字母大写;
大驼峰:所有单词首字母大写。

  • 组件名不可和HTML官方的标签名同名,组件名如果如果使用小驼峰,那么使用时,用短横线(羊肉串)或者组件名首字母大写;
  • 组件没有el选项,只有根实例存在el,组件里使用template定义模板;
  • 组件模板(html代码)只能有一个根标签;
  • 组件中的data必须是一个函数。实例中不是函数。

4.3组件的属性(标签的属性)

1.使用props来完成组件属性的声明。props是外部给组件传入的数据。而组件的data是组件内部的数据。

4.3.1使用Prop传递静态数据

①在组件内部增加配置项props来声明组件里的属性。props里面可以声明多个属性。所以是一个数组。

let myComParent = {
        props:["name","sex"], //声明了两个自定义属性
        template:`<div>
                        <p>我是p:{{msg}}</p>     
                        <p>人的信息:</p>             
                        <p>姓名:{{name}}</p>             
                        <p>性别:{{sex}}</p>             
                    </div>`,
        data:function(){
            return {
                msg:"hi"
            }
        } 
    };

②使用组件时,给属性传入数据:

<!-- 使用组件时,给属性传入值,传入的值,就可以在组件内部使用 -->
<my-com-parent name="张三疯他哥" sex=""></my-com-parent>

③总结
封装组件和封装函数进行类比:
●在组件内部用props声明的属性,相当于封装函数时声明的形参;
●使用组件时,相当于调用函数,传递实参。

4.3.2使用Prop传递动态数据

即是给组件的属性v-bind(绑定动态数据)

<my-com-parent v-bind:name="name" sex=""></my-com-parent>	

如果想把对象的所有属性作为prop进行传递,可以使用不带任何参数的v-bind(即用v-bind而不是v-bind:prop-name).

todo: {
  text: 'Learn Vue',
  isComplete: false
}
<todo-item  v-bind="todo"></todo-item>

//等价于:
<todo-item 
  v-bind:text="todo.text"
  v-bind:is-complete="todo.isComplete"

></todo-item>

奇葩情况:
在JavaScript中对象和数组是通过引用传入的(传的是地址),所以对于一个数组或对象类型的prop来说,在子组件中改变这个对象或数组苯磺酸呢将会影响到父组件的状态(data),相当于函数的形参是引用类型。

4.3.3 Prop验证

vueJS提供了对属性类型的验证、属性默认值、是否必须等。

这时props不能使用数组,而需要使用对象。

props:{
            "name":{
                type:String, //限制name属性的类型是字符串
                required:true //限制name属性是必须传入值的。
            },
            "sex":[String,Number], //限制sex属性的值可以为字符串,也可以为数字
            "age":{
                type:Number, //限制age属性的类型是数字型
                default:10 // age属性的默认值是10 。如果没有给age传值,那么age就是10。
            },
            "isadult":Boolean
        },

4.3.4单向数据流

Prop 是单向绑定的:当父组件的属性(数据)变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。
另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。

4.4.组件的事件

4.4.1绑定事件

  • HTML(标签)里的绑定方式:v-on
  • JS(Vue)里绑定方式: vue对象.$on(“事件名”)

4.4.2触发事件

vue对象.$emit(“事件名”,参数);

//子组件:
Vue.component('button-counter',{
	template: "<input type='button' v-on:click='incrementCounter' v-model='counter' />",
	data:function(){
		return {
			counter:0
		}
	},
	methods:{
		incrementCounter:function(){
			this.counter += 1
			this.$emit('increment')
		}
	}
});

//父组件:

<div id="app1">
    <p>{{ total }}</p>
    <button-counter v-on:increment="incrementTotal"></button-counter>
</div>

var app1 = new Vue({
	el: '#app1',
	data:{
		total:0
	},
	methods:{
		incrementTotal:function(){
			this.total += 1;
		}
	}
});

4.5组件的内容(插槽)

  1. 组件的内容就是标签的innerHTML。vueJS里使用**Slot(插槽)**分发内容。
  2. 将父组件的内容(DOM)放到子组件指定的位置叫作内容分发。
  3. 分类

4.5.1单个插槽

 //子组件
 let person = {      
        template:`<div>
                        <hr/>
                            <p>我是上p</p>
                            <slot></slot>
                            <p>我时下p</p>
                        <hr/>
                    </div>`
    };

//父组件:
   <div id="app">
        <person>
            <div>我是div</div>
        </person>        
    </div>

    new Vue({
        el:"#app",
        components:{
            person
        }
    });

4.5.2具名插槽

如果父级给子级传来好多DOM(HTML元素),而且需要把不同的DOM放在子组件不同位置时,需要给slot起名字。利用slot元素的特殊属性name来配置如何来分发内容。

<slot name="插槽名"></slot>
//子组件
     let person = {      
        template:`<div>
                        <hr/>
                            <p>我是上p</p>
                            <slot name="s1"></slot>
                            <p>我是中p</p>
                            <slot name="s2"></slot>
                            <p>我是下p</p>
                        <hr/>
                    </div>`
    };
//父组件
  <div id="app">
        <person>
            <div slot="s1">我是div1</div>
            <div slot="s2">我是div2</div>
        </person>        
    </div>
   new Vue({
        el:"#app",
        components:{
            person
        }
    });

4.5.3编译作用域

父组件模板的内容在父组件作用域内(父组件对应的对象的作用域)编译;子组件模板的内容在子组件作用域内编译。

//子组件
let person = {      
        template:`<div>
                        <hr/>
                            <p>我是上p:{{t}}</p>
                            <p>我是下p</p>
                        <hr/>
                    </div>`,
        data(){
            return{
            	t:"我是子组件的数据"
        	}
        }
    };
    
//父组件:
  <div id="app">
        <input :value="msg" />         
        <person v-show="s">
            <p>{{msg}}</p>
            <div>我是div1:{{msg}}</div>
        </person>
  </div>

    new Vue({
        el:"#app",        
        data:{
            msg:"hi",
            s:true
        },
        components:{
            person
        }
    });

扩展:有余力的小可爱阔以自行研究一下作用域与插槽!

4.6组件(间)的通信

vue组件之间的通信(传递数据)是必然的,依据vue组件之间的关系(父子,兄弟,或者无关组件)会有不同的做法:

  • 父子组件:props /ref/s $emit
  • 父子、隔代、兄弟组件通信 :EventBus $emit / $on
  • 集中管理,适用于所有场景:$root
  • 适用于所有场景:Vuex,路由
    下面为大家一一讲解,路由,Vuex后续讲道router、Vuex详讲解。

4.6.1父子组件

父->子:props,refs,也叫正向传值;
子->父:事件,逆向传值。

  • 父组件给子组件传值

在这里插入图片描述
props传值:就是上面所提到的prop动态传值。
①子组件

<template>
  <div>
      <!-- 使用 -->
      homezi--{{title}}---{{num}}--{{sex}}
  </div>
</template>

<script>
export default {
    // 子组件设置好了接收
    props:["title","num",'sex']
}
</script>

②父组件

<template>
  <div>
      home
      <!-- 在子组件被调用的地方 进行传递 -->
      <Homezi title="我是title" num="我是num" sex="我是sex"/>
  </div>
</template>

<script>
import Homezi from "./homezi.vue"
export default {
    components:{
        Homezi
    }
}
</script>
  • refs传值: **用标签的方式使用组件,实际就是创建了组件对象。**只要拿到组件对象,那么组件对象中的methods就可以使用。refs是vue中获取dom的一种方式,dom也就是标签,标签就是组件对象。即拿到了dom,就相当于拿到了组件对象。(这句话细细品味幺,开动你们的小脑筋)

如果某个元素使用ref属性,那么,在vue对象里,就能用this.$refs 访问。可以认为是给元素增加了个id属性,在vue里就可以操作该dom了。

格式:

    <p ref = "pId"> {{msg}}</p>

 methods:{
     testf:function(){
       	this.$refs.pId.innerHTML = "hi";
     }
}

示例:

 <!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="app">
        <input type="text" :value="str" ref="txt"> <input type="button" value="测试" @click="fn">
        <parent ref="par"></parent>
    </div>
    <script src="vue.js"></script>
    <script>
        // 定义子组件
        let son = {
                template: ` <div>
            <p>我是子组件</p>
          </div>`
            }
            // 定义组件
        let parent = {
            template: `
           <div>
            <p>我是父组件</p>
            <p>{{str1}}</p>
            <son></son>
          </div>`,
            data: function() {
                return {
                    str1: "hi,我是str1"
                }
            },
            components: {
                son
            }

        };

        let vm = new Vue({
            el: ".app",
            // 注册组件
            components: {
                parent: parent
            },
            data: {
                str: "hi"
            },
            methods: {
                fn() {
                    this.$refs.txt.type = "button";
                    this.$refs.par.str1 = "哈哈哈";
                    // console.log(this.$refs.par.str1);
                }
            }
        })
    </script>
</body>

</html>

4.6.2兄弟组件

4.6.1.1事件总线events-bus

1.vue-bus实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信。它是实现非父子组件通信的一种解决方案。
2.步骤:假如B组件给A组件传值,则B组件触发,A组件绑定事件

①单独new一个Vue空对象: let bus= new Vue();
②在组件A里,绑定一个自定义事件(相当于定义了一个自定义事件):
bus.$on(‘eclick’,target => {
console.log(target) 
})

③在组件B里,触发事件
bus.$emit(‘eclick’,“b传给a的”);

3.示例

// 定义一个vue对象(作为事件总线的对象)
let bus = new Vue();

let myCom1 = {
    template:`
        <div>
            <hr>
            组件com1
            <hr>
        </div>
    `,
    created(){
        // 注册了一个事件
        bus.$on("eclick",(target)=>{
            console.log(target);
        });        
    }
}

let myCom2 = {
    template:`
        <div>
            <input type="button" value="  传 " @click="fn" />
        </div>
    `,
    methods:{
        fn(){
            //触发事件
            bus.$emit("eclick","hello");
        }
    }
}

Vue.component("my-com1",myCom1);
Vue.component("my-com2",myCom2);

new Vue({
    el:"#app"
});

4.6.1.2集中管理($root)

把数据存到根实例的data选项,其他组件直接修改或者使用。
1.定义:

new Vue({
  data:{a:1}
})

2.使用

//子组件内部
this // 子组件本身
this.$root // vm 根实例
this.xx //组件内部数据
this.$root.a //根实例数据

4.6.3动态组件

有的时候,在不同组件之间进行动态切换是非常有用的。即页面的某个位置要显示的组件是不确定的,是会变化的。

//vue中使用的方式实现
<component :is="组件名变量">

示例:

<div id="app">
        <span @click="show(0)">娱乐</span>|<span  @click="show(1)">八卦</span>|<span @click="show(2)">体育</span>
        <div>
            <component :is="currCom"></component>
        </div>
</div>

let yuLe = {
    template:"<div>娱乐新闻</div>"
}
let eightGua = {
    template:"<div>八卦新闻</div>"
}
let sports = {
    template:"<div>体育新闻</div>"
}

new Vue({
    el:"#app",
    data:{
        currCom:"yuLe",
        coms:["yuLe","eightGua","sports"]
    },
    methods:{
        show(index){
            this.currCom = this.coms[index];
        }
    },
    components:{
        yuLe,eightGua,sports
    }
});

今天先为大家分享到这,想听后续,可以点击关注?,blue胖胖才有动力持续为您更新~

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-28 08:56:16  更:2021-08-28 08:56:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:08:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码