前端 Vue学习记录

114 阅读12分钟

本文已参与 [新人创作礼] 活动 , 一起启动掘金创作之路!


认知Vue

三大框架(vue、react、angular)

Vue主要做什么

  • 不需要操作DOM
  • 单页面应用页项目
  • 采用类似React语法,用于 微信小程序/MpVue

特点

  • 数据驱动视图
  • MVVM 双向绑定
  • 通过 指令 增强 html功能
  • 组件化 复用代码
  • 开发者只需关注数据

API

VueAPI:cn.vuejs.org/v2/api/

Vue中文社区:www.vue-js.com/

安装

安装应用的方式向引入 js代码 一样即可

  • 下载 Vue.js 库,本地引入

  • 在线 CDN 引入

    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    

Vue应用

步骤:

  1. body中,设置Vue管理的视图==
    ==
  2. 引入vue.js
  3. 实例化 Vue对象new Vue();
  4. 设置Vue实例的选项:如el、data... new Vue({选项:值});
  5. 在 ==
    == 中通过{{ }}使用data中的数据 (插值表达式
<body>
    <!-- 1. 提供容器 -->
    <div id="app">
        <p>{{str}}</p>
    </div>
    <!-- 2. 引入vue -->
    <script src="vue.js"></script>
    <script>
        // 3. 模拟数据
        new Vue({
            // 配置vue选项
            // 选择器选择容器
            el: '#app',
            // 设置数据
            data: {
                str: '测试对象'
            }
        })
    </script>
</body>

Vue生命周期

Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂在DOM、渲染-更新-渲染、卸载等过程,这些过程会运行一些叫做 生命周期钩子 的函数,提供了在不同生命周期中需要实现的功能!

首次接触Vue不建议看该章节

Vue生命周期函数分别有:

  • 创建期
    • beforeCreate
    • created
    • beforeMount
    • mounted
  • 运行期
    • beforeUpdate
    • updated
  • 销毁期
    • beforeDestroy
    • destroyed

Vue生命周期完整图:

创建期

Vue实例创建期的钩子函数,分别在不同创建执行的钩子函数

实例时间线钩子函数说明
T1 数据/方法未加载beforeCreateVue实例 初始化 后执行
T2 数据/方法刚加载createdVue实例 数据/方法 加载后执行
T3 模板刚好编译完beforeMountVue实例 HTML模板编译后执行
T4 页面渲染渲染完mountedDOM模型渲染完后执行

示例:

<div id="app">
    <p>{{msg}}</p>
</div>
....
<script>
new Vue({
    el: "#app",
    data: {
        msg: "Hello world",
    },
    methods: {
        say() {
            console.log("load...say()")
        }
    },
    // 生命周期测试
    beforeCreate() {
        // Vue实例初始化后执行(没有数据和方法
        console.log("beforeCreate() => ", this.msg)
        // 方法编译时会报错
        /* 控制台结果
        beforeCreate() =>  undefined
        * */
    },
    created() {
        // Vue实例加载数据和方法后执行
        console.log("created() => ", this.msg, this.say())
        /* 控制台结果
        load...say()
        created() =>  Hello world undefined
        * */
    },
    beforeMount() {
        // 模板编译后执行(此时页面为渲染
        console.log("beforeMount() => ",
                "html:" + document.querySelector("p").innerHTML,
                "text:" + document.querySelector("p").innerText
        )
        /* 控制台结果
        beforeMount() =>  html:{{msg}} text:{{msg}}
        * */
    },
    mounted() {
        // DOM模型渲染完后执行
        console.log("mounted() => ",
                "html:" + document.querySelector("p").innerHTML,
                "text:" + document.querySelector("p").innerText
        )
        /* 控制台结果
        mounted() =>  html:Hello world text:Hello world
        * */
    }
    
});
</script>

运行期

Vue实例在页面渲染后的期间为运行期间,当中触发钩子函数的有 数据变化

实例时间线钩子函数说明
T4+ 数据更变/页面渲染前beforeUpdate实例中的数据被 修改前执行
T5+ 数据更变/页面渲染前updated实例中的数据被 修改后执行

示例:

<div id="app">
    <p>{{count}}</p>
    <button @click="add">add</button>
</div>
....
<script>
new Vue({
    el: "#app",
    data: {
        count: 0
    },
    methods:{
        add() {
            this.count++;
        }
    },
    beforeUpdate() {
        // 实例中的数据被修改前执行
        console.log("beforeUpdate() => ",
            "this: "+this.count,
            "html: "+document.querySelector("p").innerHTML,
            "text: "+document.querySelector("p").innerText
        )
        /* 控制台数据(点击3次)
        beforeUpdate() =>  this: 1 html: 0 text: 0
        beforeUpdate() =>  this: 2 html: 1 text: 1
        beforeUpdate() =>  this: 3 html: 2 text: 2
        */
    },
    updated() {
        // 实例中的数据被修改后执行
        // 实例中的数据被修改前执行
        console.log("updated() => ",
                "this: "+this.count,
                "html: "+document.querySelector("p").innerHTML,
                "text: "+document.querySelector("p").innerText
        )
        /* 控制台数据(点击3次)
        updated() =>  this: 1 html: 1 text: 1
        updated() =>  this: 2 html: 2 text: 2
        updated() =>  this: 3 html: 3 text: 3
        */
    }
});
</script>

销毁期

Vue实例和Vue的组件生命周期一样,也有相同的功能以及选项,因此在测试应用也如此,在这一销毁期当中有两个钩子函数分别是

实例时间线钩子函数说明
T(end-1) 组件销毁前beforeDestroy实例/组件 被销毁前执行
T end 组件销毁后destroyed实例/组件 被销毁后执行

示例:

示例运用 v-if指令使 组件Element节点删除 的方式,对销毁函数产生调用

<div id="app">
    <button @click="toggle">切换</button>
    <son v-if="flag"></son>
</div>
....
<template id="son">
    <div>
        <p>我是组件</p>
    </div>
</template>
<script>
    Vue.component("son", {
        template: "#son",
        data() {
            return {
                msg: "hello"
            }
        },
        methods: {
            say() {
                console.log("Say()")
            }
        },
        beforeDestroy() {
            console.log("beforeDestroy() => 组件销毁",
                    this.msg, this.say()
            )

        },
        destroyed() {
            // 数据/方法 在组件销毁后应用 报红
            console.log("destroyed() => 组件销毁"
                    // this.msg, this.say()
            )
        }
    })
    
    new Vue({
        el: "#app",
        data: {
            flag: true
        },
        methods: {
            toggle() {
                this.flag = !this.flag;
            }
        }
    })
</script>

Vue选项

选项都是可以直接写在vue实例下的,被分为了几类:

  • 数据选项
  • DOM选项
  • 生命周期钩子 选项
  • 资源选项
  • 组合选项
  • 其他选项

由于选项众多,不能一一举例,更详细了解自行API

数据选项

data 数据

**作用:**将数据响应式同步显示视图

类型:==Object | Function==

关键字: data

数据可在指定的el容器进行数据访问。如:数据name , 视图中 {{name}} 访问数据

在容器中数据一旦发生改变,视图中的数据也会跟随改变

示例

<div id="app">
    <p>{{count}}</p>
    <p>{{msg}}</p>
    <p>{{list}}</p>
</div>
...
<script>
let vm = new Vue({
    el: '#app',
    data:{
        count: 100,
        msg:"张三最帅!",
        list: [1,2,3,4]
    }
})
vm.count = 300;
console.log(vm);
console.log("=====");
console.log(vm.count);
console.log(vm.msg);
console.log(vm.list);
console.log("=====");
console.log(vm._data);
</script>
<!-- 浏览器结果 
300

张三最帅!

[ 1, 2, 3, 4 ]
 -->
<!-- 控制台结果 (vue太长了)
Vue {...}
=====
300
张三最帅!
(4) [1, 2, 3, 4, __ob__: Observer]0: 11: 22: 33: 4length: 4__ob__: Observer {value: Array(4), dep: Dep, vmCount: 0}[[Prototype]]: Array
=====
{__ob__: Observer}
 -->

props传递

**作用:**接受父组件传值

类型:==Array | Object==

关键字: props

示例:跳转示例

methods 方法

**作用:**执行方法(函数)的操作

类型:=={ [key: string]: Function }==

**值:**method对象

关键字: methods

  • 可通过 实例对象 访问对象内的方法
  • 方法中 访问本身 属性/方法 需要 自身实例对象/this本身对象
  • method函数不建议使用箭头函数来定义,因 箭头函数会绑定上下级关系,在本对象的其他方法通过 自身实例对象/this本身对象 进行访问时,可能访问不到

书写形式:

methods:{
	<方法名1>:function(){...}
	[,<方法名2>() {...}]
}

示例

<body>
    <div id="app">
        <!-- 也可以直接调用 -->
        <!-- <p>{{fn1()}}</p> -->
        <p>{{count}}</p>
        <button v-on:click="fn1()">count++ (函数1)</button><br/>
        <button v-on:click="fn2">count++ (函数2)</button>
    </div>
    <script src="vue.js"></script>
    <script>
        let vm = new Vue({
            el: '#app',
            data:{
                count:100
            },
            methods:{
                fn1:function(){
                    console.log("调用了function()函数1");
                    // this对象本身的属性
                    vm.count++;
                },
                fn2() {
                    // vm当前实例的属性
                    console.log("调用了function()函数2");
                    this.count++;
                }
            }
        })
        // 实例对象调用
        // vm.fn1();
        // vm.fn2();
    </script>
</body>

computed 计算属性

**作用:**为属性值做数据处理,以防 插值表达式 应用逻辑复杂

类型:=={ [key: string]: Function | { get: Function, set: Function } }==

**API:**cn.vuejs.org/v2/guide/co…

关键字: computed

步骤:

  1. 在 data 定义好 数据变量

  2. 定义 计算属性 的方法

    computed:{
        <计算属性名>: function () {
            return ...;
        }
    }
    
  3. 使用计算属性 (使用方式与 插值表达式 一样 =={{<计算属性名>}}==

computed 与 methods 的区别:

  • computed直接通过 计算属性名 调用 ; 而 methods方法 采用 方法名() 调用
  • computed绑定的是 data中的数据 ; 而 methods方法 无论执行与否 都会重新计算

示例:

<p>{{msg}}</p>
<p>{{reversMsg}}</p>
// hello!
// !olleh
...
<script>
new Vue({
    el:"...",
    data:{
        msg:"hello!"
    },
    computed :{
        reversMsg: function () {
            // split() 将字符串对指定对象进行分割
            // reverse() 将数组反转
            // join() 将数组中对象拼接返回字符串
            return this.msg.split('').reverse().join('');
        }
    }
});
</script>

watch 数据监听

作用: 监听指定 数据变化时 触发的函数

类型:=={ [key: string]: string | Function | Object | Array }==

关键字: watch

步骤:

  1. 在 data 定义好 数据变量

  2. 设置监听 属性

    watch: { 
        <属性名>(newV, oldV) {...}
        [,<dat属性名2>(newV, oldV){...}...]
    }
    

computed 与 watch 的区别:

  • computed 必须有返回值 ,由于异步请求缘故,返回值可能是无效值
  • watch 无需返回值,不用管优先顺序的问题

典型事例:用户列表 (自行测试)

DOM选项

el 选择器

**作用:**指定容器vue实例管理的html视图

类型:==string | Element==

Element值: id选择器/class选择器/dom对象

关键字: el

示例:

<body>
    <!-- 提供容器 -->
    <div id="app1">
        <p>{{str}}</p>
    </div>
    <div class="app2">
        <p>{{str}}</p>
    </div>
    <div name="app3">
        <p>{{str}}</p>
    </div>
    <script src="vue.js"></script>
    <script>
        // id选择
        new Vue({
            el: '#app1',
            data: {
                str: '测试对象1'
            }
        })
        // class选择
        new Vue({
            el: '.app2',
            data: {
                str: '测试对象2'
            }
        })
        // dom对象选择
        new Vue({
            el: document.getElementsByName("app3")[0],
            data: {
                str: '测试对象3'
            }
        })
        
    </script>
</body>
<!-- 浏览器 结果 
    测试对象1

    测试对象2

    测试对象3
 -->

template 模板

作用: 组件应用的模板将会替换挂载指定组件

类型:==String==

关键字:template

示例:跳转示例

**注意:**一个模板最外层只能有一个根元素

render 渲染

**作用:**将预先注册好的组件,可通过 render()方法直接渲染

类型:==(createElement: () => VNode) => VNode==

关键字:render

标签渲染 与 render()方法渲染 的区别:

  • 标签渲染,不会覆盖Vue实例控制区域
  • render方法渲染,会覆盖Vue实例控制区域

**render()方法函数说明:**
  1. 必选,createElement:用于return虚拟DOM
  2. 可选,context:接收其他组件传递的数据

createElement参数

createElement参数是 用于创建 VNode节点 ,同时也是方法中的第一个参数

createElement创建方式

new Vue({
    el: "#app",
	render: (h) =>{
		return h("h6", {class: "abc"}, "我是h6")
	}
})

渲染结果

<div id="app">
	<h6 class="abc">我是h6</h6>
</div>

上面例的 h 是 createElement 的缩写,其中有三个形参

参数类型说明
1 必选String通过字符串解析HTML标签进行创建
2 可选Object为虚拟DOM编写属性参数等
3 可选String | Array数组视为:子虚拟DOM节点
字符串视为:标签中的内容

添加Vue指令功能以及事件点击详细了解

示例1:

<div id="app">
    
    <!-- 解释:
        插槽的作用域 和 组件子父类的作用域 不同,因此传递传递参数的方式也不同
            slot-scope : 提供过插槽传递出来的 数据集
            :msg : 传递msg数据传递给子组件应用
        PS:为了更直观的呈现应用了自定义名称传递
    -->
    <father>
        <son slot-scope="aaa" :msg="aaa.bbb"></son>
    </father>

</div>
</body>
...
<template id="father">
    <div>
        <p>我是父组件</p>
        <!-- 为当前插槽传递数据出去 -->
        <slot :bbb="say"></slot>
    </div>
</template>
<script>
    
    Vue.component("father", {
        template: "#father",
        data() {
            return {
                say: "你好我是父组件!"
            }
        }
    })
    
    Vue.component("son", {
        // 组件函数化
        functional: true,
        render: (h, context) => {
            // 接收其他组件传递的数据
            console.log(context)
            return h("h6", {class: "abc"}, context.props.msg)
        },
        props: ["msg"]
    })
    
    new Vue({
        el: "#app"
    })
</script>

渲染结果

<div id="app">
    <div>
        <p>我是父组件</p> 
        <h6 class="abc">你好我是父组件!</h6>
    </div>
</div>

资源选项

directives 自定义指令

类型:==Object==

关键字:directives

示例:跳转示例

components 组件

类型:==Object==

关键字:components

示例:跳转示例

filters 过滤器

**作用:**自定义格式化data数据

类型: ==Object==

关键字: filters

**API:**cn.vuejs.org/v2/guide/fi…

步骤:

  1. 定义过滤器 全局/局部 全局过滤器

    Vue.filter(<过滤器名称>, function (value) {
        return ...;
    });
    

    局部过滤器

    filters: {
        <过滤器名称>: function (value) {
            return ...;
        } 
        [, <过滤器名称>: function (value){...}]
    }
    
  2. 应用过滤器 (前提该标签在Vue容器范围内

    // No.1 插值表达式应用
    {{<数据>|<过滤器名称>}}
        
    // No.2 v-bind指令应用
    <p v-bind:id="<数据>|<过滤器名称>">...</p>
    

示例:

<div id="app1">
   <h2>app1</h2>
   <p>{{msg|no1}}</p>
   <p>{{msg|no2}}</p>
</div>
<div id="app2">
   <h2>app2</h2>
   <p>{{msg|no1}}</p>
   <p>{{msg|no2}}</p>
</div>
...
<script>
   // 全局过滤器 (首字母大写
   Vue.filter("no1", function (v) {
       return v.charAt(0).toUpperCase()+v.slice(1);
   });
   new Vue({
       el: "#app1",
       data: {
           msg: "hello"
       },
       // 局部过滤器 (尾字母大写
       filters: {
           no2: function (v) {
               let len = v.length;
               return v.slice(0, len - 2) + v.charAt(len - 1).toUpperCase();
           }
       }
   });
   new Vue({
       el: "#app2",
       data: {
           msg: "world"
       }
   });
</script>

带参串联应用

使用顺序与我们Java方法链式调用方法一样,可以多个过滤器串行使用

// 100元人民币
<p> {{msg|unit('元')|type('人民币')}} </p>
...
<script>
    new Vue({
        el: "#app",
        data: {
            msg: 100
        },
        filters: {
            unit: function (val, unit) {
                return val + unit;
            },
            type: function (val, type) {
                return val + type;
            }
        }
    });
</script>

日期格式处理

借助第三方插件:momentjs.cn/

CDN:cdn.staticfile.org/moment.js/2…

步骤:

  1. 引入插件 moment.js
  2. 创建格式格式化日期过滤器
  3. 格式化日期操作 ==moment(<日期对象>).format(<日期格式>)==

示例:

// 2022-03-12 18:23:46
<p>{{msg|dateFormat}}</p>
...
<script src="https://cdn.staticfile.org/moment.js/2.24.0/moment.js"></script>
<script>
new Vue({
    el: "#app",
    data: {
        msg: new Date()
    },
    filters: {
        dateFormat: function (v) {
            return moment(v).format("YYYY-MM-DD HH:mm:ss");
        }
    }
});
</script>

Vue组件

**作用:**在不同的组件共同应用时数据会相互干扰,因此要为该组件单独开辟一个单独data的地址

关键字: components(局部使用) / component (全局使用)

组件命名:

  • 组件的命名不支持 驼峰命名
  • 传递 属性/方法 也不能使用 驼峰命名
  • 驼峰命名 的应用替换至短横线分隔命名

步骤:

  1. 定义 局部/全局 Vue组件

    局部 Vue组件 (在components选项中

    components:{
    	<Vue组件名> : {
        	template: <根元素>,
        	data() {
        	    return{
        	        <key>:<value>
        	    }
        	}
    	} [, <Vue组件名2> : {...}]
    }
    

    全局 Vue组件

    Vue.component(<Vue组件名>,{
    	template: <根元素>,
    	data() {
    	    return{
    	        <key>:<value>
    	    }
    	}
    );
    
  2. 在 Vue容器中 添加 Vue组件

    <Vue组件名></Vue组件名>
    

模板应用方式

  1. Js代码中

    let tmp = '<div>...</div>';
    ...
    Vue.component(...,{
        template: tmp
    })
    
  2. script标签中

    <script id="info">
        <div>...</div>
    </script>
    ...
    Vue.component(...,{
        template: "#info"
    })
    
  3. template标签中

    <template id="info">
        <div>...</div>
    </template>
    ...
    Vue.component(...,{
        template: "#info"
    })
    

Vue组件 与 Vue实例 的区别:

  • Vue组件 data需要函数返回值。而且只能返回一个对象
  • Vue组件 没有 el选项,但有 template选项 代表页面结构(自要一个根元素
  • Vue组件之间的数据都是相互独立的,运行的 作用域、数据、逻辑 没有关联

**示例:**
<div id="app">
    <h3>组件复用</h3>
    <button-count></button-count>
    <button-count></button-count>
    <button-count></button-count>
    <br> <h3>组件共用</h3>
    <button @click="count++">按钮 {{count}}</button>
    <button @click="count++">按钮 {{count}}</button>
    <button @click="count++">按钮 {{count}}</button>
</div>
<script src="vue.js"></script>
<script>
    Vue.component('button-count', {
        data: function() {
            return {count : 0}
        },
        template:'<button @click="count++">按钮 {{count}}</button>'
    });
    new Vue({
        el: '#app',
        data:{
            count: 0
        }
    })
</script>

示例2:

<div id="app">
    <component-a></component-a>
    <component-b></component-b>
</div>
<script src="vue.js"></script>
<script>
// 全局
Vue.component("component-a",{
    template: '<div>\n' +
            '            <button @click="cut"><</button>\n' +
            '            <span>{{count}}</span>\n' +
            '            <button @click="add">></button>\n' +
            '        </div>',
    data() {
        return{
            count: 0
        }
    },
    methods:{
        add() {
            console.log("add")
            this.count++;
        },
        cut() {
            console.log("cut")
            this.count--;
        }
    }
});

new Vue({
    el:"#app",
    data:{},
    // 局部
    components:{
        "component-b" : {
            template: '<div>\n' +
                    '            <button @click="cut">减</button>\n' +
                    '            <span>{{count}}</span>\n' +
                    '            <button @click="add">加</button>\n' +
                    '        </div>',
            data() {
                return{
                    count: 0
                }
            },
            methods:{
                add() {
                    console.log("add")
                    this.count++;
                },
                cut() {
                    console.log("cut")
                    this.count--;
                }
            }
        }
    }
});
</script>

组件嵌套

嵌套情况: (其他方式嵌套不可用

  • 全局 套 全局
  • 局部 套 全局

示例:

<div id="app">
    <h1>全局 套 全局</h1>
    <parent-all-a></parent-all-a>
    <!--<h1>局部 套 局部</h1>-->
    <h1>局部 套 全局</h1>
    <parent-part-b></parent-part-b>
</div>
...
<script>
    // 全局
    Vue.component("child-all-a",{
       template:'<p>child-part-a</p>'
    });
    Vue.component("child-all-b",{
       template:'<p>child-part-b</p>'
    });
    // 全局 套 全局
    Vue.component("parent-all-a",{
        template:'<div>\n' +
                '     全局\n' +
                '     <child-all-a></child-all-a>\n' +
                '     <child-all-b></child-all-b>\n' +
                ' </div>'
    })
    
    // 局部
    new Vue({
        el:"#app",
        data:{},
        components: {
            "child-part-a":{
                template:'<p>child-part-a</p>'
            },
            "child-part-b":{
                template:'<p>child-part-b</p>'
            },
            "parent-part-b":{ // 局部 套 全局
                template:'<div>\n' +
                        '            局部\n' +
                        '            <child-all-a></child-all-a>\n' +
                        '            <child-all-b></child-all-b>\n' +
                        '        </div>'
            }
        }
    });
</script>

组件通信

由于组件之间的数据都是相互独立互不干扰,如果组件之间的数据需要交互情况可应用 props选项 绑定属性传递即可获取

组件之间的通信是根据关系划分为:

  • 父组件通信
  • 子组件通信
  • 同胞组件通信

关键字:props (数据传递) / emit (方法传递)

数据通信

关键字:props

步骤: (应用前提 Vue容器 data 包含有 msg属性

  1. 创建 Vue组件
  2. 添加 props选项 增加绑定属性(任意) ==props : [<自定义属性名>]== (数组形式可写多个绑定属性)
  3. 在引用 Vue组件 的标签 中添加绑定属性 对应的 父组件属性/Vue属性 ==<<组件名> :<绑定属性名>="<父组件属性名>"></<组件名>>==

注意:

  • 子组件的 props选项 值是一个数组
  • 数组中的值是 绑定子组件上的属性 用于接收父组件的传值
  • 子组件的 template选项 可直接使用 绑定好的属性,从而实现获取父组件传递的值
  • 子组件 更变绑定的属性值 ,不会对其父组件的 data数据有任何影响

**示例:**
<div id="app">
    <child-a :msg="msgParent"></child-a>
    <p>父组件msgParent:{{msgParent}}</p>
</div>
...
<script>
Vue.component("child-a",{
    template:'<div>\n' +
            '            <p>子组件 data.count = {{count}}</p>\n' +
            '            <p>父容器 data.msgParent = {{msg}}</p>\n' +
            '            <button @click="add">++</button>\n' +
            '        </div>',
    data() {
        return{
            count : 100
        }
    },
    methods:{
        add() {
            this.count++;
            this.msg++;
        }
    },
    // 绑定 指定的data
    props:['msg']
});
new Vue({
    el:"#app",
    data:{
        msgParent : 200
    }
})
</script>

方法通信

步骤: (前提父组件已经有方法 且可直观的呈现

  1. 父组件模板中的子类标签 添加 ==@<自定义名称>: "方法名"== (用于传递方法

    <template id="Father">
        <div>
            ...
            <!-- 传递方法 <自定义名称 parentsay> -->
            <son @parentsay="say"></son>
        </div>
    </template>
    
  2. 子类添加自定义方法,使用 ==this.$emit(<自定义名称> [, 方法的参数])== (用于回调父类的方法

    // 通过 sonFn()进行 调用父类的方法
    components: {
        "son":{
            template: "#Son",
            methods:{
                // 自定义方法 调用父类传递的方法
                sonFn() {
                    this.$emit("parentsay");
                }
            }
        }
    }
    

传递方法条件:

  • 父组件向子组件传递方法 前提需要在父组件模板中的子组件标签添加 传递的关键字
  • 子组件应用父组件中的方法 子组件必须创建自定义方法进行调用

**实例:**
<div id="app">
    <father></father>
</div>
...
<template id="Father">
    <div>
        <p>父组件</p>
        <button @click="say('父类')">按钮</button>
        <!-- 传递方法 <自定义名称 parentsay> -->
        <son @parentsay="say"></son>
    </div>
</template>
<template id="Son">
    <div>
        <p>子组件</p>
        <button @click="sonFn('子类')">按钮</button>
    </div>
</template>
...
<script>
    new Vue({
        el: "#app",
        data: {},
        components: {
            "father": {
                template: "#Father",
                components: {
                    "son":{
                        template: "#Son",
                        methods:{
                            // 自定义方法 调用父类传递的方法
                            sonFn(type) {
                                this.$emit("parentsay",type);
                            }
                        }
                    }
                },
                methods:{
                    say(type) {
                        alert(type+": 已经点击啦!")
                    }
                }
            }
        }
    })
</script>

匿名插槽

插槽 是给组件模板添加动态的数据。由于没有指定名称则默认应用匿名插槽

关键字:slot

注意:

  • 匿名插槽即将被废除,因此笔记仅借参考,建议使用具名插槽
  • 如果组件标签当中未使用标签,则使用默认插槽中的数据
  • 多个匿名插槽会拷贝多份标签中的数据进行填充

示例:

<div id="app">
    <son>
        <div>匿名插槽填坑1</div>
        <div>匿名插槽填坑2</div>
        <div>匿名插槽填坑3</div>
    </son>
</div>
....
<template id="son">
    <div>
        <div>头部</div>
        <slot>默认数据</slot>
        <div>尾部</div>
    </div>
</template>
<script>
    new Vue({
       el:"#app",
       data:{},
       components:{
           "son": {
               template:"#son"
           }
       }
    });
</script>

渲染结果:

<div id="app">
    <div>
        <div>头部</div> 
        <div>匿名插槽填坑1</div> 
        <div>匿名插槽填坑2</div> 
        <div>匿名插槽填坑3</div> 
        <div>匿名插槽填坑1</div> 
        <div>匿名插槽填坑2</div> 
        <div>匿名插槽填坑3</div> 
        <div>尾部</div>
    </div>
</div>

具名插槽

具体插槽 是通过name属性进行赋予插槽,因此可以指定使用插槽

应用方式:在模板中的 slot标签 添加属性 name属性值为名称 即可实现具体插槽

示例:

<div id="app">
   <son>
       <div slot="one">one内容11</div>
       <div slot="two">two内容22</div>
   </son>
</div>
....
<template id="son">
    <div>
        <div>头部</div>
        <slot name="one">默认内容1</slot>
        <slot name="two">默认内容1</slot>
        <div>尾部</div>
    </div>
</template>
<script>
    new Vue({
        el:"#app",
        data:{},
        components:{
            "son":{
                template:"#son"
            }
        }
    });
</script>

渲染结果:

<div id="app">
    <div>
        <div>头部</div> 
        <div>one内容11</div> 
        <div>two内容22</div> 
        <div>尾部</div>
    </div>
</div>

插槽作用域

插槽作用域 是带数据的插槽,数据在填充插槽时一般不会传递数据的因此需要手动进行传递数据,否则无法应用

传递方式有两种:

  • 具名插槽的传递 ==#<插槽名>="<自定义获取名>"==

  • 匿名插槽的传递

    ==slot-scope="<自定义获取名>"==

应用步骤:

  1. 在模板插槽的 slot标签中 添加 vue指令 ==v-bind:<数据名> = "<参数>"== (可缩写 缩写:==:names="list"== (list为名称的数组数据)
  2. 在父组件模板中的 插槽填充标签里以以下两个方式进行应用获取数据 ==#<插槽名>="<自定义获取名>"==/==slot-scope="<自定义获取名>"==

注意:

  • #<插槽名>="<自定义获取名>" 的用法是给具体插槽进行应用的
  • slot-scope="<自定义获取名>" 的用法是给 匿名/标签 插槽进行应用
  • 匿名插槽的默认名称为 default ,也可通过该插槽名称进行传递数据

**示例: **
<div id="app">
    <father></father>
</div>
....
<template id="Father">
    <son>
        <!-- 具体插槽应用 -->
        <template #one="alist">
            具体插槽 填充内容: {{alist.namelist1}}
        </template>
        <!-- 标签指定具体插槽应用 -->
        <div  slot="two" slot-scope="alist">
            标签指定具体插槽 填充内容: {{alist.namelist2}}
        </div>
        <!-- 匿名插槽应用 -->
        <template slot-scope="blist">
            匿名插槽 填充内容: {{blist.namelist3}}
        </template>
    </son>
</template>
<template id="Son">
    <div>
        <div>头部</div>
        <div>当前数据: {{list}}</div>
        <!-- 将当前与的数据进行传递给 插槽填充的数据进行应用 -->
        <!-- 指令应用原意:v-bind:<数据名> = "<参数>" -->
        <slot :namelist1="list" name="one">具体插槽 默认内容: {{list}}</slot>
        <br>
        <slot :namelist2="list" name="two">具体插槽 默认内容: {{list}}</slot>
        <br>
        <slot :namelist3="list">匿名插槽 默认内容:{{list}}</slot>
        <div>尾部</div>
    </div>
</template>
<script>
    new Vue({
        el:"#app",
        data:{},
        components:{
            "father":{
                template:"#Father",
                components:{
                    "son":{
                        template: "#Son",
                        data(){
                            return{
                                list:['张三','李四','王五','赵六']
                            }
                        }
                    }
                }
            }
        }
    })
</script>

渲染结果:

<div id="app">
    <div>
        <div>头部</div> 
        <div>当前数据: ["张三","李四","王五","赵六"]</div> 
        具体插槽 填充内容: ["张三","李四","王五","赵六"]
        <br> 
        <div>标签指定具体插槽 填充内容: ["张三","李四","王五","赵六"]
        </div> 
        <br> 
        匿名插槽 填充内容: ["张三","李四","王五","赵六"]
        <div>尾部</div>
    </div>
</div>

插值表达式

**作用:**将绑定的数据实时的显示出来

形式:=={{插值表达式}}==

**用法:**JS表达式、三目运算符、方法调用

示例

<body>
    <div id="app">
        <!-- js表达式 -->
        <p>{{1+2+3}}</p>
        <p>{{1>2}}</p>
        <p>{{name+'很帅'}}</p>
        <p>{{count+1}}</p>
        <!-- 三目运算 -->
        <p>{{count===1?"成立":"不成立"}}</p>
        <p>{{list}}</p>
        <!-- 方法调用 -->
        <p>{{ip.split('.').reverse().join(':')}}</p>
    </div>
    <script src="vue.js"></script>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                name: '张三',
                count: 1,
                list: [1,2,3].reverse(),
                ip: "127.0.0.1"
            }
        })
    </script>
</body>
<!-- 浏览器结果
6
false
张三很帅
2
成立
[ 3, 2, 1 ]
1:0:0:127
 -->

Vue指令

v-text与v-html

v-text

  • 作用:更新 整个 标签中的内容
  • 插值表达式:更新标签中局部内容

v-html

  • 作用:更新 标签中的 内容和标签
  • 可渲染html标签的内容
  • 经量避免使用防止XSS脚本攻击

示例

<body>
    <div id="app">
        <!-- v-text指令的值会替换标签内容 -->
        <p v-text="msg">老哥 真的很帅</p>
        <!-- v-html指令的值(包括标签字符串)会替换掉标签的内容 -->
        <p v-html="msg2">老哥 真的很帅</p>
    </div>
    <script src="vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                msg: '老鸽',
                msg2:'<span>老鸽2</span>'
            }
        })
    </script>
</body>

v-if与v-show

v-if

  • 作用:布尔值 决定元素的 添加 或 删除
  • 值:布尔值
  • 用于 条件少改变 的应用

v-show

  • 作用:布尔值 决定元素的 显示 或 隐藏
  • 值:布尔值
  • 用于 频繁切换 的应用

示例

<body>
    <div id="app">
        <p v-if="isShow">张三</p>
        <p v-show="isShow">李四</p>
    </div>
    <script src="vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                isShow: false
            }
        })
    </script>
</body>

<!-- 浏览器 审查元素查看结果
<div id="app">
    
    <p style="display: none;">李四</p>
</div>
->

v-on

**作用:**指令监听 DOM事件 ,进行 JS响应

**值&事件:**使用方式 (两种)

  1. ==v-on:事件名="方法名"==
  2. ==@事件名="方法名"==

**修饰符:**封装逻辑的方法

使用:==@事件名.修饰符="方法名"== @contextmenu.prevent

**事件对象:**向方法返回对象的本身

  1. 方法名传参 $event 传递 ==方法名($event)==
  2. 默认第一个event事件参数 ==方法名== (实参接收时传递的第一个参数是 event对象)

element.preventDefault() 阻止默认事件行为

**API:**cn.vuejs.org/v2/guide/ev…

监听事件

监听事件说明
@click鼠标点击
@keyup键盘点击

事件修饰符

修饰符说明
.once只触发一次
.prevent阻止 默认事件行为
.stop阻止 冒泡函数行为
.self只响应当前元素触发的行为(会受 冒泡影响
.capture添加事件监听器

示例

<body>
    <div id="app">
        <p>{{count}}</p>
        <!-- 应用 -->
        <!-- 触发按钮事件 -->
        <button v-on:click="add">v-on Add1</button><br>
        <button @click="add">@ Add1</button><br>
        <!-- 修饰符 -->
        <!-- 只能点击一次 -->
        <button @click.once="add">.noce Add1</button><br>
        <!-- 禁止右键菜单 -->
        <button @contextmenu.prevent="add" @click="add">.prevent Add1</button><br>
        <!-- 获取事件对象 -->
        <button @click="add($event)">($event) add1</button><br>
        <button @click="add2">add2</button><br>
    </div>
    <script src="vue.js"></script>
    <script>
        new Vue({
            el: '#app',                                     
            data: {
                count:1
            },
            methods:{
                add(e){
                    console.log(e);
                    this.count++;
                },
                add2(e){
                    console.log(e);
                    this.count++;
                }
            }
        })
    </script>
</body>

<!--
执行方法测试
-->

v-for

  • 作用:渲染指定数组列表(遍历数组)
  • 值:==item in items== 或 ==item of items== ( items 是数组的别名
  • 支持参数选项 item(迭代数组的单个元素)、index(下标数)、key (主键)
  • 如果数组使用有 key ,则每个元素都要有 key ,而且 key 是唯一的
  • v-for 写的位置 不是父级标签,而是 重复本身的标签!!(循环的是标签本身

使用带有 key 的数组 ,更新会更快, 因 根据 key 的更变进行更变,key 是需要手动指定

示例

<body>
    <div id="app">
        <p>in 和 of</p>
        <p><span v-for="item in list">{{item}} </span></p>
        <p><span v-for="item of list">{{item}} </span></p>
        <p>============</p>

        <!-- v-for 支持参数选项 -->
        <p>index 选项</p>
        <ul v-for="(item , index) in items">
            <li>{{index}} : {{item.name}}---{{item.sex}} </li>
        </ul>
        <p>============</p>
        <p>key 选项</p>
        <ul>
            <li v-for="(v,i) in items":key="i">{{v}}  ---  {{i}}</li>
        </ul>
        <ul>
            <li v-for="(v,i,k) in json":key="k">{{i}} -- {{k}} -- {{v}}</li>
        </ul>

    </div>
    <script src="vue.js"></script>
    <script>
        let vm = new Vue({
        el: "#app",
            data: {
                list : ['a','b','c','d'],
                items:[
                    {name:"张三",sex:"男"},
                    {name:"李四",sex:"女"},
                    {name:"王五",sex:"男"},
                    {name:"赵六",sex:"男"}
                ],
                json : {
                    "001":{name:"智乃"},
                    "002":{name:"琪露诺"},
                    "003":{name:"蕾姆"},
                    "004":{name:"猫羽雫"}
                }
            }
        })
    </script>
</body>

<!-- 浏览器结果 

in 和 of

a b c d

a b c d

============

index 选项

0 : 张三---男
1 : 李四---女
2 : 王五---男
3 : 赵六---男
============

key 选项

{ "name": "张三", "sex": "男" } --- 0
{ "name": "李四", "sex": "女" } --- 1
{ "name": "王五", "sex": "男" } --- 2
{ "name": "赵六", "sex": "男" } --- 3
001 -- 0 -- { "name": "智乃" }
002 -- 1 -- { "name": "琪露诺" }
003 -- 2 -- { "name": "蕾姆" }
004 -- 3 -- { "name": "猫羽雫" }

 -->

v-bind

**作用:**绑定标签中上任意属性,对此属性值进行动态同步

**值:**值对象/[数组对应值] (支持三目运算符

**参数:**指定属性对应的值

编写:==v-bind:<属性名>== 缩写为: ==:<属性名>==

id

==:id="<变量名>"==

// id指定的值为 "myId"
<p :id="ID"></p>
data: {
	ID:"myId";
}

class

Model:==:class="{<类值>:<布尔值> [, <类值>:<布尔值>]}"==

Model:==:class="<属性名>"== (指定的是对象

原生class:==:class="[<类名> [, <类名>] ]"==

注意:

  • 绑定class和原生class 不会合并重复,会优先去Model中找数据值
  • 如果想在当中使用原生class样式名,将对象以数组的形式写进去,以防在Model中查找
  • 例如: :class="['box']" (可以写多个原生class类名)

<!-- class 对象 -->
<!-- class结果值为:class="left right left" -->
<p class="left right" :class="{left:a,rigth:b}"></p>
<!-- class 数组 -->
<!-- class结果值为:class="left right left2 rigth2" -->
<p class="left right" :class="[aa,bb]"></p>
<!-- class 封装对象 -->
<!-- class结果值为:class="a" -->
<p :class="obj"></p>
data: {
	a:true,
	b:false,
    aa: "left2",
    bb: "rigth2",
	obj:{
		a:true,
		b:false
	}
}

style

==:style="{<样式名>:<样式值> [, <样式名>:<样式值>]}"==

==:style="[<变量名/对象名> [, <变量名/对象名>] ]"==

注意:

  • 如果用对象形式,则样式值一定要有 单引号/双引号 包围,否则样式无效
  • 数组形式可以 直接写入样式 或 对象样式

<!-- style 对象 -->
<p :style="{background:a,width:b,height:c}"></p>
<!-- style 数组 -->
<p :style="[aa,bb,cc]"></p>
data: {
    a : "black",
    b : "100px",
    c : "100px",
    aa : {"background":"red"},
    bb : {"width":"100px"},
    cc : {"height":"100px"},
}

v-model

  • 作用:绑定表单组件上任意属性,对此值进行动态同步
  • 值:变量名

作用标签

标签绑定属性值
==input[type='text']==value
==textarea==value
==input[type='checkbox']==checked
==input[type='radio']==checked
==select>option==value

注意: v-model 会忽略表单组件中的 value、checked、selected attribute 的初始值,而数据的来源在 Vue 实例中

示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <!--
         - text 和 textarea 元素使用 value property 和 input 事件
         - checkbox 和 radio 使用 checked property 和 change 事件
         - select 字段将 value 作为 prop 并将 change 作为事件
     -->
    <form action="#">
        <!-- text -->
        <input type="text" v-model="msg" value="柏竹">
        <p>{{msg}}</p>
        <!-- textarea -->
        <textarea v-model="msg2" cols="30" rows="3"></textarea>
        <p>{{msg2}}</p>
        <!-- radio -->
        sex:
        <label>女<input type="radio" value="女" name="sex" v-model="picked"></label>
        <label>男<input type="radio" value="男" name="sex" v-model="picked"></label>
        <p>check:{{picked}}</p>
        <!-- checkbox -->
        hobby:
        <label> <input type="checkbox" name="hobby" value="篮球" v-model="checked">篮球</label>
        <label> <input type="checkbox" name="hobby" value="网球" v-model="checked">网球</label>
        <label> <input type="checkbox" name="hobby" value="足球" v-model="checked">足球</label>
        <label> <input type="checkbox" name="hobby" value="羽毛球" v-model="checked">羽毛球</label>
        <label> <input type="checkbox" name="hobby" value="乒乓球" v-model="checked">乒乓球</label>
        <label> <input type="checkbox" name="hobby" value="气排球" v-model="checked">气排球</label>
        <p>checked:{{checked}}</p>
        <!-- select -->
        <select v-model="selected">
            <option value="篮球" selected>篮球</option>
            <option value="网球">网球</option>
            <option value="足球">足球</option>
            <option value="羽毛球">羽毛球</option>
            <option value="乒乓球">乒乓球</option>
            <option value="气排球">气排球</option>
        </select>
        <p>selected:{{selected}}</p>
    </form>
</div>
</body>
<script src="vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            msg:"张三",
            msg2:"李四",
            picked: '',
            checked:[],
            selected:''
        }
    });
</script>
</html>

v-cloak

**作用:**解决页面初次渲染时 出现 {{}} 的问题

步骤:

  1. v-cloak指令 添加CSS规则

    [v-cloak] { display: none; }
    
  2. 为 vue实例的容器 添加 指令 v-cloak

    <div id="app" v-cloak>
        ...
    </div>
    

v-once

作用: 在所在的元素只渲染一次

步骤: 为指定标签 添加 v-once指令 (前提该标签在Vue容器范围内

v-slot

**作用:**指定当前标签中的子标签内容填充至插槽中(点击插槽了解

编写:==v-slot:<插槽名>== 缩写为:==#<插槽名>==

注意 :

  • 该指令只能用在 template标签 中进行使用该该指令
  • v-slot指令 vue2.6以上版本才能应用

示例:

<div id="app">
    <son>
        <template v-slot:one>
            <p>模板数据填充1</p>
            <p>模板数据填充11</p>
        </template>
        <template #two>
            <p>模板数据填充2</p>
            <p>模板数据填充22</p>
        </template>
    </son>
</div>
....
<template id="son">
    <div>
        <div>头部</div>
        <slot name="one">默认数据1</slot>
        <slot name="two">默认数据2</slot>
        <div>尾部</div>
    </div>
</template>
<script>
    new Vue({
       el:"#app",
       data:{},
       components:{
           "son":{
               template:"#son"
           }
       }
    });
</script>

渲染结果:

<div id="app">
    <div>
        <div>头部</div> 
        <p>模板数据填充1</p> 
        <p>模板数据填充11</p> 
        <p>模板数据填充2</p> 
        <p>模板数据填充22</p> 
        <div>尾部</div>
    </div>
</div>

自定义指令

**作用:**对 DOM元素 进行底层操作

类型: 全局/局部 自定义指令

**API:**cn.vuejs.org/v2/guide/cu…

步骤:

  1. 定义 自定义指令 全局/局部 全局自定义指令

    Vue.directive(<指令名称>, {
        <钩子函数>: function (e [, <参数>]) {
        	// e参数 DOM对象本身
        	...
        }
    })
    

    局部自定义指令

    new Vue({
        el: "...",
        data: {...},
        directives: {
            <指令名称1>:{
                <钩子函数>: function (<钩子函数参数>) {
                    ...
                }
            } [,
            <指令名称2>:{
                <钩子函数>: function (<钩子函数参数>) {
                    ...
                }
            }]
        }
    });
    
  2. 在指定元素添加 自定义指令 实现功能 ==v-<指令名称>==

钩子函数

  • bind :只调用一次,指令第一次绑定到元素时调用
  • unbind :只调用一次,指令与元素解绑时调用
  • inserted :被绑定元素插入父节点时调用

钩子函数参数

  • el :被绑定的当前元素的 DOM对象
  • binding :指令本身数据,包含有以下属性
    • name :指令名称 不包括 v- 前缀
    • value :指令绑定值 包含表达式运算结果 如 v-my="1+1" 最后结果值为 2
    • expression :字符串形式的指令表达式(属性名
    • arg :传给指令的参数 v-my:funcc 中 ,则 参数为 funcc
    • modifiers :包含修饰符的对象 v-my.foo.bar 中,修饰符对象为 {foo: true , bar: true}

示例:

<div id="app">
    <div v-demo:foo.a.b="msg"></div>
</div>
...
<script>
new Vue({
    el: "#app",
    data: {
        msg: "hello"
    },
    directives: {
        demo: {
            bind: function (el, binding, vnode) {
                // 将  binding对象 转化为 JOSN格式
                var s = JSON.stringify;
                el.innerHTML = 
                        'name : ' + s(binding.name) + "<br>" +
                        'value : ' + s(binding.value) + "<br>" +
                        'expression : ' + s(binding.expression) + "<br>" +
                        'arg : ' + s(binding.arg) + "<br>" +
                        'modifiers : ' + s(binding.modifiers) + "<br>" +
                        'Object.keys : ' + Object.keys(vnode).join(',');
            }
        }
    }
});
</script>
//控制台
name : "demo"
value : "hello"
expression : "msg"
arg : "foo"
modifiers : {"a":true,"b":true}
Object.keys : tag,data,children,text,elm,ns,context,fnContext,fnOptions,fnScopeId,key,componentOptions,componentInstance,parent,raw,isStatic,isRootInsert,isComment,isCloned,isOnce,asyncFactory,asyncMeta,isAsyncPlaceholder

Vue属性

key

**作用:**在虚拟DOM中的节点添加 ID

**缘故:**在数组遍历时可能出现相同DOM节点的元素,容易出现数据混乱的问题,因此需要独有的key进行排列调整,这一前提key必须具有唯一性

<ul>
	<li v-for="item in items" :key="item.id">...</li>
</ul>

应用场景:

强制替换元素/组件而不是重复使用

  • 完整地触发组件的生命周期钩子
  • 触发过渡
<!-- 当 text 发生改变时,<span> 总是会被替换而不是被修改,因此会触发过渡。 -->
<transition>
      <span :key="text">{{ text }}</span>
</transition>

ref

**作用:**获取被 ref属性 的标签 DOM对象(该标签在Vue容器范围内

值: DOM对象获取的引用

注意:

  • 当 ref 和 v-for 共存时,得到的 DOM对象 将会是一个包含对应数据源子组件数组
  • $ref 只会在标签渲染后生效,并非是响应式的,因此竟可能的避免在 模板/算法 中使用
  • $ref 也可获取组件标签中的 DOM对象 信息

**步骤: **

  1. 为需要获取 DOM对象的标签添加 ref属性 并赋予值
  2. 获取 DOM对象 可直接通过以下方式获取 ==this.$refs.<ref属性值>==

示例:

<div id="app">
    <son ref="myMsg"></son>
    <button @click="log">log</button>
</div>
....
<template id="son">
    <div>
        <p>我是组件</p>
        <p>{{msg}}</p>
    </div>
</template>
<script>
    
    Vue.component("son", {
        template: "#son",
        data() {
            return{
                msg:"hello"
            }
        },
        methods:{
            say() {
                console.log("load... Say()")
            }
        }
    })
    
    new Vue({
        el: "#app",
        data: {
            msg: "hello"
        },
        methods: {
            log() {
                console.log(this.$refs.myMsg)
                console.log(this.$refs.myMsg.msg)
                console.log(this.$refs.myMsg.say)
            }
        }
    });
</script>

slot

**作用:**标记往哪个具名插槽中插入子组件内容

示例:跳转示例

slot-scope

**作用:**接收插槽传递的数据

示例:跳转示例

Vue通信

作用: 在 Vue.js 中发出请求(本质和Ajax一样

**API:**www.kancloud.cn/yunye/axios…

**API2:**cn.vuejs.org/v2/cookbook…

**API3 : ** www.axios-http.cn/docs/intro

**CDN:**unpkg.com/axios@0.26.…

**开源:**www.npmjs.com/package/jso…

关键字:json-serveraxios.js

插件应用前提:(可跳过) 本地调用的 json库,如果没有通过以下步骤操作

  1. 安装 node.jsnodejs.org/zh-cn/
  2. 配置环境 将node.js根路径 配至 Path 变量中 (添加值,并非覆盖
  3. 测试安装 cmd 执行指令 ==node -v== (返回版本号代表成功
  4. 安装 Json本地调试 cmd执行命令 ==npm i json-server==/==npm install -g json-server== (其中一个
  5. 配置 Window脚本运行策略 (系统默认是未签名运行
    1. 菜单搜索 powershell (管理员运行)
    2. 更改签名 执行命令 ==set-ExecutionPolicy RemoteSigned==
  6. 任意一终端(cmd) 执行 ==json-server <数据文件.json>== (手动指定路径/终端跳转到指定路径下

json-server 指令选项

参数简写[类型] 默认值说明
--config-c[String] "json-server.json"指定配置文件
--port-p[Number] 3000设置端口
--host-H[String] "localhost"设置域
--watch-w[boolean]是否监听
--routes-r[String] ""指定自定义路由
--middlewares-m[Array]指定中间件 files
--static-s[String]设置静态目录
--read-only--ro[boolean]只允许 GET请求
--no-cors--nc[boolean]是否禁用 跨域资源共享
--no-gzip--ng[boolean]是否禁用 GZIP 内容编码
--id-i[String] "id"设置数据库 id 属性
--delay-d[Number]增加响应延迟(ms)
--snapshots-S[String] "."设置快照目录
--foreignKeySuffix--fks[String] "Id"设置外键后缀
--quiet-q[boolean]禁止输出中的日志消息
--help-h[boolean]显示帮助信息
--version-v[boolean]显示版本号

步骤:

  1. 引入插件 axios.js

  2. 启动 json-server本地库

  3. 请求语法

    axios.get(url).then((res) => {
    	// 请求成功 会来到这 res响应体
    }).catch((err) => {
    	// 请求失败 会来到这 处理err对象
    })
    

其他请求实例 (用户列表

// 获取
axios.get('http://localhost:3000/brands').then().catch()
// 删除
axios.delete('http://localhost:3000/brands/1').then().catch()
// 添加
axios.post('http://localhost:3000/brands', {name: '小米', date: new Date()}).then().catch()
// 修改
axios.put('http://localhost:3000/brands/1', {name: '小米', date: new
Date()}).then().catch()
// get模糊搜索
axios.get("http://localhost:3000/brands?name_like=" + "aaa").then().catch()

注意:

  • 选项computed 计算属性查询 返回的结果是行不通,因 查询请求是异步返回数据的
  • 选项computed 计算属性 一定要是同步操作,异步逻辑则失效
  • 异步请求可通过 选项watch 监听 data数据

## 请求头配置

请求头一般关注的属性有 :

  • Content-Type
  • Accept

axios.js库 通信默认使用 json格式 , 如果自定义以下的格式 :

  • ==application/json== (默认)
  • ==application/x-www-form-urlencoded==
  • ==multipart/form-data==

模板用例 :

axios.post(
    URL, params, 
    { headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        '
    } })
    .then(res => {
	  if (res.data.code === 0) {
	        this.$router.go(-1)
	  }
	}).catch(error => {
	  alert('更新用户数据失败' + error)
	})

ue路由

作用: 让 页面 构建单页应用变得简单

CDN: lib.baomitu.com/vue-router/…

**API:**router.vuejs.org/zh/api/

关键字: routerroutes

注意:

  • js库引入顺序 优先引入vue后则引入vue-router(基于vue运行的)
  • 路由的参数传递 需要到 $route对象 进行传递参数
  • router-link标签 渲染默认是 a标签,如有想渲染其他标签,可通过 tag属性值为 指定的标签名

应用步骤:

  1. 引入 vue 和 vue-router库

  2. 设置 HTML内容

    <div id="app">
        <!-- router-link 最终会被渲染成a标签,to指定路由的跳转地址 -->
    	<router-link to="/users">用户管理</router-link>
    	<router-link to="/home">首页展示</router-link>
    	<!-- 路由匹配到的组件将渲染在这里 -->
    	<router-view></router-view>
    </div>
    
  3. 创建 路由对应的Vue组件的模板

    let Home = {
    	template: '<div>这是Home内容</div>'
    };
    let Users = {
    	template: '<div>这是用户管理内容</div>'
    };
    
  4. 配置路由规则 routes不建议更变 (在实例对象中,如果更变了名称则匹配不到该对象

    let routes = [
    	{ path: '/users', component: Users }
    	{ path: '/home', component: Home }
    ];
    
  5. 实例路由对象 router不建议更变 (在实例对象中,如果更变了名称则匹配不到该对象

    let router = new VueRouter({
        routes
    })
    
  6. router实例 挂载到 vue实例上

    new Vue({
    	el: '#app',
    	router
    })
    

示例:

<div id="app">
    <!-- 2. 设置HTMl内容 -->
    <!-- router-link 最终会想渲染成a标签,to指定路由的跳转地址 -->
    <router-link to="/home">主页</router-link>
    <router-link to="/top">热点</router-link>
    <router-link to="/abouts">关于</router-link>
    <!-- <显示的内容> -->
    <router-view></router-view>
</div>
<!-- 1. 引入库 -->
<script src="vue.js"></script>
<script src="vue-router.js"></script>
<script>
    // 4. Vue组件
    let Home = {
        template:"<div>主页内容</div>"
    }
    let Top = {
        template:"<div>热点内容</div>"
    }
    let Abouts = {
        template:"<div>关于内容</div>"
    }
    
    // 3. 设置路由规则
    let router = new VueRouter({
        routes: [
            {path:"/home",component: Home },
            {path:"/top",component: Top },
            {path:"/abouts",component: Abouts }
        ]
    });
    
    // 5. 把router实例挂载到vue实例上
    new Vue({
        el: "#app",
        router
    });
</script>

动态路由

动态路由 是 通过在跳转过程对参数的一个携带过程,在当中有两种方式进行传递数据

  • 原生URL
  • 动态路由Path携带 (REST风格

应用步骤:

  1. 设置HTML内容,并引入参数 (假如传递参数 : =={name: '张三', age: 23}==

    <!-- 原生URL传参 -->
    <router-link to="/item?name=张三&age=23">张三1</router-link>
    <!-- 动态路由传参 -->
    <router-link to="/item/张三/23"></router-link>
    
  2. 动态路由规则 动态参数进行接收,接收方式 :<参数名> (参数的属性名称随意

    new VueRouter({
        routes:[
            {path:'/item/:name/:age',component: ...}
        ]
    })
    

    **PS:**原生URL传递无需经通过第二步骤进行 Path路由地址的设置

  3. 两种传递方式接收各有不同 (因 $route对象 存储参数位置不一样

    • 原生URL:==this.$route.query.<参数名>==
    • 动态路由:==this.$route.params.<参数名>==

**PS:**路由跳转时可在组件中添加 update()函数 ,在DOM重新渲染后,对数据进行打印

示例:

<div id="app">
    <router-link to="/item?id=23">小明</router-link>
    <router-link to="/item?id=23&name=小华">小华</router-link>
    <router-link to="/item/33/小军">小军</router-link>
    <router-view></router-view>
</div>
....
<template id="show">
    <div>
        <p>传递的数据查看</p>
        <ul>
            <li>params.id: {{this.$route.params.id}}</li>
            <li>params.name: {{this.$route.params.name}}</li>
            <li>params.age: {{this.$route.params.age}}</li>
            <li>query.id: {{this.$route.query.id}}</li>
			<li>query.name: {{this.$route.query.name}}</li>
			<li>query.age: {{this.$route.query.age}}</li>
        </ul>
    </div>
</template>
<script>
    
    let Items = {
        template: "#show",
        // DOM 重新渲染完成后被调用 (用于测试
        updated() {
            console.log(this.$route);
        }
    }
    
    let router = new VueRouter({
        routes: [
            {path: '/item/:id', component: Items},
            {path: '/item/:id/:name/:age', component: Items}
        ]
    })
    
    new Vue({
        el: "#app",
        router
    })
</script>

路由 to属性赋值

路由的 to属性 可提高路由的利用和便捷

  1. 常规跳转 ==aaa==
  2. 变量值 ==aaa==
  3. 对象name跳转 ==aaa==
  4. 对象path跳转 ==aaa==
  5. 带参数跳转 ==aaa==

示例:

<div id="app">
    <!-- 常规 -->
    <router-link to="/aaa">aaa</router-link>
    <!-- 变量 -->
    <router-link :to="bbb">bbb</router-link>
    <!-- 对象name -->
    <router-link :to="{name:'ccc'}">ccc</router-link>
    <!-- 对象path -->
    <router-link :to="{path:'/ddd'}">ddd</router-link>
    <!-- 带参数跳转 -->
    <router-link :to="{name:'eee',params:{id:1,name:'张三'}}">eee</router-link>
    <br>
    <router-view></router-view>
</div>
...
<script>

    let AAA = {
        template:'<div>AAA</div>'
    }
    let BBB = {
        template:'<div>BBB</div>'
    }
    let CCC = {
        template:'<div>CCC</div>'
    }
    let DDD = {
        template:'<div>DDD</div>'
    }
    let EEE = {
        template:'<div>EEE<br>参数: {{$route.params.id}} : {{$route.params.name}} </div>'
    }
    
    let router = new VueRouter({
        routes:[{
            path:"/aaa",
            component: AAA
        },{
            path:"/bbb",
            component: BBB
        },{
            name:"ccc",
            path:"/ccc",
            component: CCC
        },{
            path:"/ddd",
            component: DDD
        },{
            name:"eee",
            path:"/eee",
            component: EEE
        }]
    })
    
    new Vue({
        el:"#app",
        data:{
            bbb:'/bbb'
        },
        router
    })

</script>

redirect重定向

当某个页面被强制中转时,采用 redirect 进行路由重定向

关键字:redirect

步骤: 在原有的路由组件里 添加新 属性 ==redirect : <路由地址>==

routes:[{
    path : <默认路由地址>,
    redirect : <重定向路由地址>
}]

实例:(将 /bbb 路由强制中转至 /aaa

<div id="app">
    <router-link to="/aaa">aaa</router-link>
    <router-link to="/bbb">bbb</router-link>
    <router-link to="/ccc">ccc</router-link>
    <router-view></router-view>
</div>
....
<script>
    let AAA = {
        template:'<div>AAA</div>'
    }
    let BBB = {
        template:'<div>BBB</div>'
    }
    let CCC = {
        template:'<div>CCC</div>'
    }
    
    let router = new VueRouter({
        routes:[{
            path:'/aaa',
            component:AAA
        },{
            path:'/bbb',
            redirect:"/aaa",
            component:BBB
        },{
            path:'/ccc',
            component:CCC
        }]
    });
    
    new Vue({
        el:"#app",
        data:{},
        router
    });
</script>

编程式导航

以 点击事件形式 来点击某一标签,实现路由跳转功能

关键字:this.$router.push

步骤: 在 Vue容器添加方法用于 事件响应,执行 this.$router.push对象

<方法名>() {
    this.$router.push({
        path:<路由地址>
    });
}

示例:(按钮实现路由AAA

<div id="app">
    <router-link to="/aaa">aaa</router-link>
    <button @click="toAAA">aaa编程式</button>
    <router-view></router-view>
</div>
...
<script>
    
    let AAA = {
        template:'<div>AAA</div>'
    }
    
    let router = new VueRouter({
        routes:[{
            path:'/aaa',
            component:AAA
        }]
    });
    
    new Vue({
        el:"#app",
        data:{},
        methods:{
            toCCC() {
                this.$router.push({
                    path:"/aaa"
                });
            }
        },
        router
    });
</script>

路由激活样式

路由激活会产生样式 ==calss="router-link-exact-active router-link-active"==,该类会伴随着激活出现

<a href="..." class="router-link-exact-active router-link-active">切换页面1</a>

以上的 激活样式的系统类名,一般不建议直接覆盖系统默认的样式,因此官方提供有方式修改其样式

自定义路由激活class样式 :在路由规则中 添加 linkActiveClass属性其值为 class名

路由激活渲染示例: (la-active为自定义样式的class名)

<a href="..." class="router-link-exact-active la-active">切换页面1</a>

路由嵌套

路由嵌套和二级菜单 类似,但二级路由的嵌套是通过组件模板中再次添加路由,从而实现路由嵌套的效果

关键字:children

应用步骤:

  1. 在一级路由组件的 component模板中 添加二级路由的模板
  2. 在一级路由的路由规则里 添加属性 children数组
  3. childern数组 中配置二级路由规则与模板
let routes = [{
        path: <一级路由地址>,
        component: <一级路由模板>,
        children: [
            {path: <二级路由地址>, component: <二级路由模板>}
            [,{path: <二级路由地址>, component: <二级路由模板>}...]
        ]
    }
    [,{path:  <一级路由地址>, component: <一级路由模板2>}...]
]

注意:

  • 该路由为子路由,那么无需再次编辑一级路径地址,也可无需添加反斜杠 /

**示例1:**
<div id="app">
    <router-link to="/home">主页</router-link>
    <router-link to="/music">音乐</router-link>
    <router-view></router-view>
</div>
...
<script>
    let Home = {
        template:'<div>Home---</div>'
    }
    let Music = {
        template: '<div>MUSIC---' +
                '<router-link to="/music/pop">流行</router-link>' +
                '<router-link to="/music/cal">古典</router-link>' +
                '<router-view></router-view>' +
                '</div>'
    }
    //二级组件
    let Detail = {
        template: '<div>Detail--{{$route.params.name}}</div>'
    }
    
    let router = new VueRouter({
       routes:[{
           name:'default',
           path:'/',
           component: Home
       },{
           name:'home',
           path:'/home',
           component: Home
       },{
           name:'music',
           path:'/music',
           component: Music,
           // 子路由
           children:[{
               path:'/music/:name',
               component: Detail
           }]
       }]
    });
    
    new Vue({
        el:"#app",
        data:{},
        router
    });
</script>

示例2:

<style>
    
	.box-red {
        background: red;
        height: 200px;
    }
    
    .box-blue {
        background: blue;
        height: 200px;
    }
    
    .box-green {
        background: green;
        height: 200px;
    }
</style>
....
<div id="app">
    <router-link to="/one">路由页面1</router-link>
    <router-link to="/two">路由页面2</router-link>
    <router-view></router-view>
</div>
....
<template id="one">
    <div class="box-green">
        <p>一级one</p>
        <router-link to="/one/onesub1">路由页面1</router-link>
        <router-link to="/one/onesub2">路由页面2</router-link>
        <router-view></router-view>
    </div>
</template>
<template id="onesub1">
    <div class="box-red">
        <p>二级one</p>
    </div>
</template>
<template id="onesub2">
    <div class="box-blue">
        <p>二级one</p>
    </div>
</template>
<template id="two">
    <div class="box-green">
        <p>一级two</p>
    </div>
</template>
<script>
    let One = {
        template: "#one"
    }
    let Two = {
        template: "#two"
    }
    let OneSub1 = {
        template: "#onesub1"
    }
    let OneSub2 = {
        template: "#onesub2"
    }
    
    let routes = [
        {path: "/", redirect: '/one'},
        {
            path: "/one",
            component: One,
            children: [
                {path: "onesub1", component: OneSub1},
                {path: "onesub2", component: OneSub2}
            ]
        },
        {path: "/two", component: Two}
    ]
    
    let router = new VueRouter({
        routes
    })
    
    new Vue({
        el: "#app",
        router
    })
</script>

命名视图

命名视图 是让不同出口显示不同内容(和 具名插槽 类似)

当路由地址被匹配时同时制定多个出口,并且每个出口显示的内容不一样

应用步骤:

  1. router-view标签 添加 name属性(指定出口类型的模板
  2. 在 路由规则配置中 将路由模板从 component属性 改为 components属性 (添加模板组
let router = new VueRouter({
    routes: [{
        path: <路由地址>,
        // key值 对应路由出口的 name属性值
        components: {
            <key>: <模板1>
            [,<key>: <模板2>...]
        }
    }]
})

示例:

<div id="app">
    <router-view></router-view>
    <router-view name="name1"></router-view>
    <router-view name="name2"></router-view>
</div>
....
<template id="one">
    <div>
        <p>第一个模板</p>
    </div>
</template>
<template id="two">
    <div>
        <p>第二个模板</p>
    </div>
</template>
<script>
    let One = {
        template: "#one"
    }
    let Two = {
        template: "#two"
    }
    
    // 首次打开网页URL路由地址为 '/'
    let routes = [{
        path: "/",
        components: {
            name1: One,
            name2: Two
        }
    }]
    
    let router = new VueRouter({
        routes
    })
    
    new Vue({
        el: "#app",
        router
    })
</script>

渲染结果:

<div id="app">
    <!----> 
    <div><p>第一个模板</p></div> 
    <div><p>第二个模板</p></div>
</div>

三个出口:

  1. 未指定出口名称因此没有显示
  2. 指定出口名称为 name1 -> One
  3. 指定出口名称为 name2 -> Two

路由监听

[watch属性](#watch 数据监听) 不仅仅能够监听数据的变化,还能够监听路由地址的变化

监听方式:

watch: { 
    "$route.path"(newV, oldV) {
    	console.log(newV, oldV)
    }
}

Vue其他

过渡动画

Vue 内置的过渡组件,transition 组件用于嵌套要实现过渡效果,在当中的组件 添加/删除 实现了 进入/离开 的过渡效果

关键字:transition

步骤:

  1. 先创建 transition组件,且设置 name属性 (一定要name属性

    <transition name="my">
        <!-- 产生动画的标签 -->
    </transition>
    
  2. transition组件 内设置 产生过渡动画的标签,并添加 ==v-if=<boolean是否显示>==属性

  3. 添加样式实现即可

过渡动画 class样式 :

class样式的前缀名称为 transition标签 中的 name属性值

进入 class样式

class(transition标签 name属性值为fade说明
==fade-enter==进入 初始状态
==fade-enter-to==进入 结束状态
==fade-enter-active==进入 过渡效果

离开 class样式

class(transition标签 name属性值为fade说明
==fade-leave==离开 初始状态
==fade-leave-to==离开 结束状态
==fade-leave-active==离开 过渡效果

示例:

<style>
    *{
        margin: 0;
        padding: 0;
    }
    .box {
        width: 200px;
        height: 200px;
        background: #00A1DA;
        /*绝对定位:相对浏览器*/
        position: absolute;
    }
    button{
        position: absolute;
        top: 200px;
    }
    .my-enter-to,
    .my-leave{
        left: 0;
        /*透明度*/
        opacity: 1;
    }
    .my-enter,
    .my-leave-to{
        left: 200px;
        opacity: 0;
    }
    .my-enter-active,
    .my-leave-active{
        /*过渡效果连写*/
        transition: all 2s;
    }
</style>
...
<div id="app">
    <transition name="my">
        <div class="box" v-if="isShow"></div>
    </transition>
    <button @click="toShow">按钮</button>
</div>
...
<script>
    new Vue({
        el: "#app",
        data: {
            isShow: true
        },
        methods: {
            toShow() {
                this.isShow = !this.isShow;
            }
        }
    });
</script>

Vuex

Vuex 是 Vue中的一套 公共数据管理工具,可将数据存到 vuex中,方便整个程序在任何组件 获取和修改当中的公共数据

**API:**vuex.vuejs.org/zh/

GitHub: github.com/vuejs/vuex

**CDN:**cdn.bootcdn.net/ajax/libs/v…

关键字: storestate

应用步骤: (前提:两层嵌套组件)

  1. 引入 vue.js

  2. 创建 实例vuex对象

    const <vuex对象名> = new Vuex.Store({
        state() {
            return {
                <key>:<value>
              	[, <key>:<value> ...]
            }
        }
    });
    
  3. 父组件引入 vuex对象 ==store: <vuex对象名>==

    Vue.component(<组件名>, {
        store: <vuex对象>,
    }
    
  4. 应用 vuex数据,获取通过 插值表达式 进行获取

    ==this.$store.state.<属性key>==

示例:

<div id="app">
    <grandpa></grandpa>
</div>
....
<template id="grandpa">
    <div>
        <p>爷爷 {{this.$store.state.msg}}</p>
        <father></father>
    </div>
</template>
<template id="father">
    <div>
        <p>父亲 {{this.$store.state.msg}}</p>
        <son></son>
    </div>
</template>
<template id="son">
    <div>
        <p>儿子 {{this.$store.state.msg}}</p>
    </div>
</template>
<script>
    
    const d = new Vuex.Store({
        state() {
            return {
                msg: "hello world"
            }
        }
    });

    // 爷爷
    Vue.component("grandpa", {
        template: "#grandpa",
        store: d,
        components: {
            // 父亲
            "father": {
                template: "#father",
                components: {
                    // 儿子
                    "son": {
                        template: "#son"
                    }
                }
            }
        }
    })

    new Vue({
        el: "#app"
    })
</script>

渲染结果:

<div id="app">
    <div>
        <p>爷爷 hello world</p>
        <div>
            <p>父亲 hello world</p>
            <div>
                <p>儿子 hello world</p>
            </div>
        </div>
    </div>
</div>

方法共享

方法共享 可在不同组件之间均可使用的方法,vuex中 mutations对象 是专门保存操作共享数据的方法

关键字: mutations

一般情况不建议在组件中对Vuex共享数据直接修改,因为在多个组件中维护起来会比较麻烦。因此建议使用vuex共享的方法进行修改,维护时只需查看vuex的方法即可

注意:

  • mutations中定义的方法,系统会自动传递 state参数(state保存的是共享数据

**应用步骤:** (前提:两层嵌套组件)
  1. 引入vuex.js

  2. 创建 实例Vuex对象

  3. Vuex对象中编写方法

    const <vuex对象名> = new Vuex.Store({
        state() {
            return {....}
        },
        mutations: {
            // 系统会自动传递 state参数
            <方法名1>(state) {
                ....
            }
            [,<方法名2>(state) {....}]
        }
    })
    
  4. 父组件引入 vuex对象 ==store: <vuex对象名>==

  5. 组件方法调用vuex共享 ==this.$store.commit(<vuex对象方法名>[,<参数>])==

示例:

<div id="app">
    <no1></no1>
</div>
....
<template id="no1">
    <div>
        <button @click="add"></button>
        <button @click="sub"></button>
        <input type="text" :value="this.$store.state.count">
        <no2></no2>
    </div>
</template>
<template id="no2">
    <div>
        <button @click="add2"></button>
        <button @click="sub2"></button>
        <input type="text" v-model.number="val">
        <p>{{this.$store.state.count}}</p>
    </div>
</template>
<script>
    const b = new Vuex.Store({
        state() {
            return {
                count: 1
            }
        },
        mutations: {
            // 系统会自动传递 state参数
            mAdd(state) {
                state.count += 1;
            },
            mSub(state) {
                state.count -= 1;
            },
            // 带参测试
            mAdd2(state , num) {
                state.count += num;
            },
            mSub2(state , num) {
                state.count -= num;
            }
        }
    })
    
    Vue.component("no1", {
        template: "#no1",
        store: b,
        components: {
            "no2": {
                template: "#no2",
                data() {
                    return {
                        val: 0
                    }
                },
                // 组件2 带参应用
                methods: {
                    add2() {
                        this.$store.commit("mAdd2", this.val)
                    },
                    sub2() {
                        this.$store.commit("mSub2", this.val)
                    }
                }
            }
        },
        methods: {
            add() {
                this.$store.commit("mAdd")
            },
            sub() {
                this.$store.commit("mSub")
            }
        }
    })
    
    new Vue({
        el: "#app"
    })
</script>

计算属性共享

[计算属性](#computed 计算属性) 是为了在多组件中完好的利用缓存,从而提高效率

关键字: getters

应用步骤:(上面已经有大致步骤,因此展示主要代码)

  1. 在 vuex实例中 添加 getters

    const <vuex对象名> = new Vuex.Store({
        state() {
            return{
                msg: "柏竹"
            }
        },
        getters: {
            //  系统会自动传递 state参数
            <计算属性名>(state) {
                console.log("执行了 formart")
                return state.msg + " Hello World "
            }
        }
    })
    
  2. 组件调用计算属性 ,获取通过 插值表达式 进行获取 ==this.$store.getters.<计算属性名>==

示例:

<div id="app">
    <no1></no1>
</div>
....
<template id="no1">
    <div>
        <p>no1 {{this.$store.getters.formart}}</p>
        <p>no11 {{this.$store.getters.formart}}</p>
        <no2></no2>
    </div>
</template>
<template id="no2">
    <div>
        <p>no2 {{this.$store.getters.formart}}</p>
        <p>no22 {{this.$store.getters.formart}}</p>
    </div>
</template>
<script>
    const b = new Vuex.Store({
        state() {
            return{
                msg: "柏竹"
            }
        },
        getters: {
            formart(state) {
                console.log("执行了 formart")
                return state.msg + " Hello World "
            }
        }
    })
    
    Vue.component("no1",{
        template:"#no1",
        store: b,
        components:{
            "no2":{
                template: "#no2"
            }
        },
        data() {
            return{
                msg: "柏竹"
            }
        }
    })
    
    new Vue({
        el:"#app"
    })
</script>

Vue-Cli

Vue-cli 存在的意义就是让开发人员把精力放在业务的代码上,因此其他的准备的工作交给vue-cli去做即可

**API:**cli.vuejs.org/zh/guide/

安装

全局脚手架

npm i -g @vue/cli

验证安装(查看版本

# 后面的 V 一定要大写
vue -V

创建项目

PS:项目名当中不能含有英文大写

# 4.0下创建 heroes项目
$ vue create heroes 
# 切换到 项目根目录
$ cd heroes
# 在开发模式下 启动运行项目
$ npm run serve
....
# 打包项目
$ npm run build

以上指令在 ==package.json==文件 看到相关配置

项目配置

根目录下的 ==vue.config.js==文件

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  	transpileDependencies: true,
    lintOnSave: true, 	// 在保存代码的时候开启eslint代码检查机制
    devServer: { 		// 实时保存、编译的配置段
		open: true,  	// 自动开启浏览器
		port: 12306 	// 服务运行端口
	}
})

项目目录

以下的Vue-Cli生成的项目结构解读

Vue-Cli不同版本的项目结构也会不同:

  • ==2.x==版本 的项目结构中有 buiild文件夹和config文件夹 这两个文件夹存储了webpack相关的配置,当中可以根据项目需求修改webpack配置
  • ==3+==版本 以后的版本项目结构中 已经隐藏了这两个文件夹 (主要目的是为了让初学者更关心怎么去用Vue,并非是 webpack配置相关的
.
|-- node_modules 		// 项目需要的依赖包
|-- public 				// 静态资源存储目录
| 	 |-- index.html 	// 项目主容器文件
| 	 |-- favicon.ico 	// 项目默认索引图片
|-- src
| 	 |-- assets 		// 静态资源文件夹
| 	 |-- components 	// 公共组件目录
| 	 |-- views 			// 业务组件目录
| 	 |-- App.vue 		// 顶层根基路由组件
| 	 |-- main.js 		// 主入口文件
| 	 |-- router.js		// 路由配置文件
|-- .editorconfig 		// 代码规范配置文件
|-- .eslintrc.js 		// eslint代码规范检查配置文件
|-- .gitignore 			// git上传需要忽略的文件格式
|-- babel.config.js 	// babel配置文件
|-- package-lock.json 	// 依赖包版本锁定文件
|-- package.json 		// 项目基本信息配置文件
|-- postcss.config.js 	// css预处理器配置文件
|-- vue.config.js 		// webpack 配置文件

项目开发

开发主要应用有:Vuex、Router

在开发的时候编写代码主要围绕着 src/public 这两个文件夹,他们分别作用已经在上面叙述有。开发当中可能会受到不同版本的影响,因此专门分为 版本2版本3+ 进行写开发应用示例

默认情况下生成 Vue-Cli脚手架 是官方已经配置好的,因此建议手动配置一次保存为好

手动配置安装选项:

dart-sassbabelroutervuexeslint

? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with 3.x
? Use history mode for router? (Requires proper server setup for index fallback in production) y
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save, Lint and fix on commit
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) n

版本2开发

由于版本3 较为简洁说明用版本2

main.js

// 导入 库
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

// 创建实例
new Vue({
  router,
  store,
  // 渲染组件
  render: h => h(App)
}).$mount('#app')

App.vue

// 组件模板
<template>
</template>

// 组件脚本
<script>
export default {}
</script>

// 样式
<style lang="scss">
</style>

Vuex

./router/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vue)

const store = new Vuex.Store({
  state: {
    name: '柏竹'
  }
})
// 暴露出去 给 App.vue 引用
export default store

Router

./store/index.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const router = new Router({
  routes: [...]
})

export default router

版本3+开发

main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App).use(store).use(router).mount('#app')

App.vue

<template>
</template>

<script>
export default {}
</script>

<style lang="scss">
</style>

Vuex

./router/index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    name: '柏竹'
  }
})

Router

./store/index.js

import { createRouter, createWebHistory } from 'vue-router'
// 假设引入的 One组件/Two组件
import One from '../components/One'
import Two from '../components/Two'

const routes = [
  { path: '/one', name: 'one', component: One },
  { path: '/two', name: 'two', component: Two }
]

const router = createRouter({
  // 使路由切换产生web页面历史记录
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

版本3应用示例

示例应用应用前把 src/public 文件夹的子文件清空(并非清空文件夹)

./public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webapp</title>
</head>
<body>
    <div id="app"></div>
</body>
</html>

./src/main.js

import { createApp } from 'vue'
import App from './App.vue'
import store from './store/index'
import router from './router/index'

createApp(App)
  .use(store)
  .use(router)
  .mount('#app')

./src/App.vue

<template>
    <div>
        <h2>Vuex应用测试</h2>
        <p>我是App组件{{ msg }}</p>
        <button @click="say">sayLog</button>
        <br>
        <button @click="getName">App=>getName</button>
        <h2>路由组件展示</h2>
        <router-link to="/one">Go to One</router-link>
        <br>
        <router-link to="/two">Go to Two</router-link>

        <router-view></router-view>
    </div>
</template>

<script>

export default {
  name: 'App',
  data () {
    return {
      msg: '12'
    }
  },
  methods: {
    say () {
      console.log('App组件:我太难了')
    },
    getName () {
      console.log(this.$store)
      console.log(this.$store.state.name)
    }
  }
}
</script>

<style scoped>
p {
    color: red;
}
</style>

./src/store/index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    name: '柏竹'
  }
})

模板

./src/components/One.vue

<template>
  <div>
    <p>我是One组件</p>
    <button @click="getName">One=>getName</button>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: 'One',
  methods: {
    getName () {
      console.log(this.$store.state.name)
    }
  }
}
</script>

<style scoped>
  p{
    background: red;
  }
</style>

./src/components/Two.vue

<template>
  <div>
    <p>我是Two组件</p>
  </div>
</template>

<script>
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: 'Two'
}
</script>

<style scoped>
p{
  background: blue;
}
</style>

./src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import One from '../components/One'
import Two from '../components/Two'

const routes = [
  { path: '/one', name: 'one', component: One },
  { path: '/two', name: 'two', component: Two }
]

const router = createRouter({
  // 使路由切换产生web页面历史记录
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

呈现方式自行测试

问题

  1. 项目编辑验证不规范异常问题 **解决方案:**手动配置,在IDEA配置 搜索 ESLint ,执行以下操作项

    • 选中 自动ESLint配置
    • 打钩 运行时 ==eslint --fix== 并配置 保存时操作 ==自动ESLint配置==
  2. 项目首次 ==new Vue({})== 指定无效问题 (有两种解决方案)

    1. 解决方案:(Vue-Cli3版本以下可解决 为代码添加以下注解 跳过检查

      import Vue from 'vue'
      import App from './App.vue'
      
      /* eslint-disable no-new */
      new Vue({
        el: '#app',
        render: h => h(App)
      })
      

      3以上的版本 ,因为 new实例的组件未使用因此报错 不允许在赋值/比较之外使用 new实例操作

    2. 解决方案:(Vue-Cli3版本以上的 指定创建组件应用

      import { createApp } from 'vue'
      import App from './App.vue'
      
      createApp(App).mount('#app')
      

风格指南

必要的

必要的规则会帮你规避错误,所以学习并接受它们带来的全部代价吧

组件命名

组件命名是尽可能以多个单词为组件的名称,至少两个以上

反例:OnetodoTodo

好例:no-oneNoOnetodo-itemTodoItem

data选项

组件中的 data选项 必须是以函数形式返回

组件data如果没有使用函数返回,那么可能会出现数据跨组件的现象

export default {
  data () {
    return {
      foo: 'bar'
    }
  }
}

Prop选项

组件中 Prop选项 定义尽可能详细看,至少指定传递数据的类型

**好处:**在开发环境下,可避免Vue提示出的警告

反例:

props: ['status']

好例:

props: {
  status: String
}

v-for指令

v-for的使用总要伴随 key 的使用,主要避免遍历的 DOM模型 相同的情况

v-for/v-if指令

永远不要同时使用 v-forv-if 的指令

建议方案:

  • 使用 计算属性 进行替换列表 进行过滤列表
  • 如果指定的是 列表容器 ,那么将 v-if 移至 列表容器

反例:

<!-- 指定 li 列表的遍历条例 展示
	users(Array):用户数据集 
	user.isActive(boolean):指定用户是否显示
-->
<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
<!-- 指定 li 列表 展示
	shouldShowUsers(boolean):
-->
<ul>
  <li
    v-for="user in users"
    v-if="shouldShowUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

好例:

<!-- activeUsers : 计算属性 -->
<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
...
'activeUsers':{
	return this.users.filter((user)=>{
		return user.isActive
	})
}
<!-- 实例2 -->
<ul v-if="shouldShowUsers">
  <li
    v-for="user in users"
	:key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

组件样式作用域

在组件中的 样式设置 默认是全局的,全局的情况会导致 其他组件 样式也会受到影响

style标签 中添加 scoped属性 进行限制作用域(仅限于自身组件

私有 函数名

组件暴露出去后,当中的方法如果和公开的API函数名称冲突,为了避免该问题的出现,建议使用:$_ 作为前缀

反例: updateupdate$update

好例:

// 示例1
var myGreatMixin = {
  // ...
  methods: {
    $_myGreatMixin_update: function () {
      // ...
    }
  }
}
// 示例2 (更好的
var myGreatMixin = {
  // ...
  methods: {
    publicMethod() {
      // ...
      myPrivateFunction()
    }
  }
}

function myPrivateFunction() {
  // ...
}

export default myGreatMixin

强烈推荐

推荐

慎用

Vue案例

代码自行复制应用

商品购物列表

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

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        #app {
            width: 600px;
            margin: 10px auto;
        }
        
        .tb {
            border-collapse: collapse;
            width: 100%;
        }
        
        .tb th {
            background-color: #0094ff;
            color: white;
        }
        
        .tb td,
        .tb th {
            padding: 5px;
            border: 1px solid black;
            text-align: center;
        }
        
        .add {
            padding: 5px;
            border: 1px solid black;
            margin-bottom: 10px;
        }
    </style>
</head>

<body>
<div id="app">
    <div class="add">
        品牌名称:
        <input type="text" v-model="name">
        <button :disabled="name.length===0" @click="addItem">添加</button>
    </div>
    
    <div class="add">
        品牌名称:
        <input type="text" placeholder="请输入搜索条件" v-model="searchVal">
    </div>
    
    <div>
        <table class="tb">
            <tr>
                <th>编号</th>
                <th>品牌名称</th>
                <th>创立时间</th>
                <th>操作</th>
            </tr>
            <tr v-for="(item,index) in newList" :key="index">
                <td>{{index+1}}</td>
                <td>{{item.name}}</td>
                <td>{{formatDate(item.date)}}</td>
                <td>
                    <a href="#" @click="delItem(index)">删除</a>
                </td>
            </tr>
            <tr v-if="newList.length === 0">
                <td colspan="4">没有品牌数据</td>
            </tr>
        </table>
    </div>
</div>
<script src="./vue.js"></script>
<script src="http://cdn.staticfile.org/moment.js/2.24.0/moment.js"></script>
<script>
    // 准备数据
    let vm = new Vue({
        el: "#app",
        data: {
            list: [
                {name: "张三", date: new Date},
                {name: "李四", date: new Date},
                {name: "王五", date: new Date},
                {name: "赵六", date: new Date}
            ],
            // 存储用户输入的数据
            name: '',
            isShow: false,
            searchVal:''
        },
        methods: {
            addItem() {
                //添加
                for (let item of this.list) {
                    if (item.name == this.name) {
                        alert("不能重复");
                        return;
                    }
                }
                this.list.push({name: this.name, date: new Date});
                this.name = '';
            },
            
            delItem(index) {
                if (confirm("是否删除 " + this.list[index].name)) {
                    this.list.splice(index, 1);
                }
            },
            formatDate(date){
                return moment(date).format("YYYY-MM-DD  HH:mm:ss");
            }
        },
        computed: {
            newList: function () {
                return this.list.filter((v) => {
                    // startsWith()
                    return v.name.startsWith(this.searchVal);
                });
            }
        }
    });

</script>
</body>

</html>

用户列表

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

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        #app {
            width: 600px;
            margin: 10px auto;
        }
        
        .tb {
            border-collapse: collapse;
            width: 100%;
        }
        
        .tb th {
            background-color: #0094ff;
            color: white;
        }
        
        .tb td,
        .tb th {
            padding: 5px;
            border: 1px solid black;
            text-align: center;
        }
        
        .add {
            padding: 5px;
            border: 1px solid black;
            margin-bottom: 10px;
        }
    </style>
</head>

<body>
<div id="app">
    <div class="add">
        Name:
        <input type="text" v-model="name">
        <button :disabled="name.length===0" @click="addItem">添加</button>
    </div>
    
    <div class="add">
        FindName:
        <input type="text" placeholder="findName" v-model="searchVal">
    </div>
    
    <div>
        <table class="tb">
            <tr>
                <th>Number</th>
                <th>ID</th>
                <th>Name</th>
                <th>Date</th>
                <th>Exe</th>
            </tr>
            <tr v-for="(item,index) in newList":key="item.id">
                <td>{{index+1}}</td>
                <td>{{item.id}}</td>
                <td>{{item.name}}</td>
                <td>{{formatDate(item.date)}}</td>
                <td>
                    <a href="#" @click="delItem(item.id)">删除</a>
                </td>
            </tr>
            <tr v-if="newList.length === 0">
                <td colspan="5">没有数据</td>
            </tr>
        </table>
    </div>
</div>
<script src="./vue.js"></script>
<script src="http://cdn.staticfile.org/moment.js/2.24.0/moment.js"></script>
<script src="https://unpkg.com/axios@0.26.1/dist/axios.js"></script>
<script>
    // 准备数据
    let vm = new Vue({
        el: "#app",
        data: {
            list: [],
            // 存储用户输入的数据
            name: '',
            searchVal: '',
            size: 0
        },
        methods: {
            addItem() { // 添加
                let node = this.list.find((v) => {
                    return v.name === this.name;
                });
                if (node != null) {
                    alert("不能重复");
                    return;
                }
                axios.post('http://localhost:3000/brands',
                        {id:this.size,name: this.name, date: new Date}).then((res)=>{
                    console.log("add:Yes")
                    this.loadDate()
                    this.name = '';
                }).catch((err)=>{
                    console.log("add:No")
                    console.log(this.size)
                    console.log(this.name)
                    this.name = '';
                });
            },
            delItem(id) { // 删除
                if (confirm("确认删除["+id+"]?")) {
                    axios.delete('http://localhost:3000/brands/' + id).then((res) => {
                        console.log("del:Yes")
                        this.loadDate()
                    }).cache((err) => {
                        console.log("del:No")
                    });
                }
            },
            formatDate(date) { // 格式化日期
                return moment(date).format("YYYY-MM-DD  HH:mm:ss");
            },
            loadDate(){ //数据加载
                console.log("loadDate...")
                axios.get("http://localhost:3000/brands").then((res) => {
                    this.list = res.data;
                    this.size = this.list.length + 1;
                    // console.log(res.data)
                }).catch((err) => {
                    console.log(err)
                });
                
            }
        },
        mounted(){ // 首次加载执行
            this.loadDate();
        },
        computed: {
            // 新表
            newList: function () {
                if (this.list.length === 0) return [];
                if (this.searchVal === '') return this.list;
                return this.list.filter((v) => {
                    return v.name.startsWith(this.searchVal);
                });
            }
        }
    });

</script>
</body>
</html>

react