当前位置:   article > 正文

Java-Vue基础_vue在java环境中的使用

vue在java环境中的使用

Vue基础语法(看官方的文档更快)

一、vue是什么

他是一个渐进式的前端框架。

1-2、vue怎么使用

<!--首先引入vue.js文件-->
<script type="text/javascript" src="js/vue.js"></script>
<!--创建一个挂载对象-->
<div id="#app">
    <div>
        {{msg}}
    </div>
</div>
<!--创建一个vue对象,然后设置对应的值-->
<script type = "text/javascript">
    var vm =new Vue({
        el: "#app",
        data: {
            msg:"hello vue"
        }
    });
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

二、vue指令

1.1、是什么

  • vue指令就是自定义的属性

1.2、怎么用

  • 直接把对应指令写在属性的位置就行了

1.3、原理

  • 在个对应的标签添加指令之后,后台选择出对应指令然后设置相应的样式和操作

例如:v-cloak指令:他是把display属性设置为None,通过隐藏vue差值表达式来修复闪动的bug

1、vue常用指令

建议查看帮助文档

v-text:填充文本

v-html:填充html如果是跨域请求会有安全问题

v-pre: 填充原始信息,会跳过编译过程显示原本的格式,如差值表达式{{msg}}

v-once:只进行一次编译,显示后不会根据后台对该值的修改而更改。只渲染一次

v-model:双向数据绑定

v-bind:绑定属性。如< a v-bind:href=“url”>之后url就可以从变量中来取了。简写格式为< a :href=“url”>

2、 数据响应式

什么是响应式

  • 一个数据的变化会引起其他数据的变化。如:屏幕尺寸变化引起页面变化

什么是数据绑定

  • 一个数据在页面上的值和javascript中的值绑在一起。可以将变量的值填充到页面中

双向数据绑定

  • 用户改变页面内容,影响数据内容变化。修改数据值,会影响数据显示。

MVVM设计思想

image-20201101173839276.png

3、事件处理

image-20201101174511494.png

4、事件修饰符

说明

用于控制事件的触发后之后的动作该怎么处理(详细都在帮助文档中)

image-20201101200644192.png

2-2-5按键修饰符

image-20201102094826313.png

<!--用来打印键盘对应的keycode-->
<input type="text" v-on:keyup="keybogdkeycodes" v-model="info"></inpt>
<input type="text" v-on:keyup.65="keybogdkeycodes" v-model="info"></inpt>
<input type="text" v-on:keyup.aaa="keybogdkeycodes" v-model="info"></inpt>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    
    Vue.config.keyCodes.aaa=65
    
    var vm =new Vue({
        el:'#app',
        data:{
            info: "hello vue !!!"
        },
        methods:{
            keybogdkeycodes:function(event){
                console.log(event.keyCode)
            }
        }
    });
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

练习1:小的计算器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2>Simple Computer</h2>
    <div id="app">
        Value A :<input type="text" v-model="a"><br/>
        Value B :<input type="text" v-model="b"><br/>
        <button v-on:click="hanlders">run</button>
        <div>result: {{result}}</div>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" >
        var vm = new Vue({
            el: "#app",
            data:{
                a:"",
                b:"",
                result:""
            },
            methods:{
                hanlders:function(){
                    this.result = parseInt(this.a)+parseInt(this.b)
                }
            }
        })
    </script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

5、v-model实现原理

<div id="app">
    <div>{{msg}}</div>
    <input type="text" v-bind:vlaue="msg" v-on:input="handle">
    <input type="text" v-bind:vlaue="msg" v-on:input="msg=$event.target.value">
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" >
    var vm = new Vue({
        el: "#app",
        data: {
            msg:"hello"
        },
        methods: {
            handle:function(event){
                this.msg=event.target.value;
            }
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

6、 v-bind属性操作

v-bind绑定了类属性之后通过类中数据的true or false来判断是否存在类中的属性名

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style type="text/css">
        .active {
            border: 1px solid red;
            width: 100px;
            height: 100px;
        }
        .error {
            background-color:yellow;
        }
    </style>
</head>
<body>
    <div id="app">
        <div v-bind:class="{active:isActive,error:isError}"></div>
        <button v-on:click="handle">switch</button>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" >
        var vm = new Vue({
            el: "#app",
            data: {
                isActive: true,
                isError: true
            },
            methods: {
                handle:function(event){
                    this.isActive = !this.isActive,
                    this.isError = !this.isError
                }
            }
        })
    </script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

v-bind:class 绑定数组

通过对变量的控制来控制class数组中数据是否存在。

<div id="app">
    <div v-bind:class="[ActiveClass,ErrorClass]"></div>
    <button v-on:click="handle">switch</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" >
    var vm = new Vue({
        el: "#app",
        data: {
            isActive: true,
            isError: true,
            ActiveClass: active,
            ErrorClass: error
        },
        methods: {
            handle:function(event){
                this.isActive = !this.isActive,
                    this.isError = !this.isError
            }
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

样式绑定中数组绑定和对象绑定可以结合使用。如果之前就有一个类了,那么类不会被覆盖

v-bind:属性

和绑定类一样有两种操作方式一种是使用类,一种是使用数组

<div id="app">
    <div v-bind:style="{border:bloada,width:widths,height:heights}"></div>
    <div v-bind:style="[borderClass]"></div>
    <button v-on:click="handle">switch</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" >
    var vm = new Vue({
        el: "#app",
        data: {
            bloada: "1px solid red" ,
            widths: "100px",
            heights: "100px",
            borderClass: {
                width: "100px",
                height: "100px",
                border: "2px solid blue"
            }
        },
        methods: {
            handle:function(event){
                this.isActive = !this.isActive,
                this.isError = !this.isError
            }
        }
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

7、分支循环

v-if :判断条件使用逻辑符号来链接 ,判断是否要渲染他

v-else-if

v-else

v-show 根据结果显示是否把当前数据显示在页面中。已经渲染了,但是肯能不显示

如果渲染数量比较少的情况下最好使用v-show因为判断的开销较大

<div id="app">
    <span v-if="datas>90">youxiu</span>
    <span v-else-if='datas >70 && datas < 90'>lianghao</span>
    <span v-else>bujige</span>
    <span v-show="showdata">hello</span>

</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    var vm =new Vue({
        el:"#app",
        data:{
            datas:1,
            showdata: true
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

v-for 循环结构

当使用数组的时候打印的是数组里面的数据,使用对象的时候打印的是对象的数据值。

<ul>
    <li v-for='item in fruits'>item</li>
</ul>
<!--使用index,item的时候回根据前面对应的位置来打印,(索引,数据)名字无所谓主要是位置的事情-->
<ul>
    <li v-for='(index,item) in fruits'>{{index+'-------'+item}}</li>
</ul>
<!--遍历数组对象的时候可以使用双层嵌套。如果furits2是数字的话,功能就类似python总的range-->
<!--也可以在第一层循环中使用对象.属性的这种方式-->
<ul v-for='item in fruits2'>
    <li v-for='(items,index) in item'>{{items+'-------'+index}}</li>
    <li >{{item.pingguo}}之类的,前提是每个数组中的数据是一样的</li>
</ul>
<script type="text/javascript">
    var vm =new Vue({
        el:"#app",
        data:{
            fruits:["pingguo","juzi","xiangjiao","tiancheng"],
            fruits1:{
                pingguo:"hahaha",
                yaoli:"aljdfjals",
                gugu:"fjaj"
            },
            fruits2:[
                     {
                         pingguo: "4212",
                         juzi:"123342",
                         boluo:"131"
                     },
                     {
                         da: "132322",
                         eee:"123223",
                         eeeaaa:"323"
                     },
                     {
                         gba: "123232",
                         qwerqr:"3123",
                         heerahhah:"3131"
                     },
                     {
                         qretr: "312",
                         hhaa:"123",
                         agag:"1331"
                     },
                     {
                         gwe: "132",
                         ewww:"12323",
                         qq:"1342341"
                     }
                 ]
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

image-20201102172741361.png

key可以帮助vue在一定程度上提高性能。根据key来减少系统对对象辨识度的开销

选项卡练习

<div id="app">
    <div id="tab">
        <ul>
            <li :class='currentIndex==index ? "active" : "" ' v-for="(item,index) in list" :key="item.id" @click="handler(index)">{{item.title}}{{item.id}}</div>
        </ul>
    <div :class='currentIndex==index ? "current" : "tabs" ' v-for="(item,index) in list" :key="item.id">
        <img :src="item.url" >
    </div>
</div>

</div>

<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app",
        data:{
            currentIndex:0,
            list:[{
                id:1,
                title:"origin",
                url:"img/1.jpg"
            },{
                id:2,
                title:"apple",
                url:"img/2.jpg"
            },{
                id:3,
                title:"peach",
                url:"img/3.jpg"
            }]
        },
        methods:{
            handler:function(index){
                this.currentIndex = index
            }
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

三、Vue过滤器

<div id="app">
<p>{{msg | msgrun("a1","b2","c3")}}</p>
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script >
    Vue.filter("msgrun",function(msg,a,b,c){
        return msg.replace(/单纯/g,a+b+c)
    })
    var vm=new Vue({
        el:"#app",
        data:{
            msg:"单纯的孩子是不存在的,只有不单纯的孩子才完美"
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

1、使用过滤器过滤时间

Vue.filter("timeFormate",function(dtstr){
    var dt = new Date(dtstr)
    var y =  dt.getFullYear()
    var m = dt.getMonth()+1
    var d = dt.getDate()

    return y+"-"+m+"-"+d
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、局部过滤器

过滤器在调用的时候才用的是就近原则,所以会先调用局部过滤器。

filters:{
    formate:function(dtstr){
        var dt = new Date(dtstr)
        var y =  dt.getFullYear()
        var m = dt.getMonth()+1
        var d = dt.getDate()

        return y+"-"+m+"-"+d+"```````````````"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

ES6的新特性填充指定长度的字符串

String.padStart(指定长度,填充字符串)//在头部填充

String.padEnd(指定长度,填充字符)//在尾部填充

3、修饰符

自定义修饰符

Vue.config.keyCodes.name = 113(对应的键盘码)
  • 1

自定义聚焦

documnet.getElementById(“”).foucuss()

定义全局的指令,定义的时候不需要添加v-前缀,但是再调用的时候需要添加v-前缀,
参数为位一个对选哪个,有一些钩子函数可以在指定的时间来完成相应的东西
Vue.directive("focus",{
    //所有函数第一个参数一定是el表示绑定的对象
    //每当质量绑定到元素上的时候,会立即执行这个bind函数,只执行一次
    bind:function(el){
        //绑定的时候还没有渲染出来,没有办法进行聚焦
        //el.focus()
    },
    //插入到dom中的时候回执行函数
    inserted:function(el){
        el.focus()
    },
    //执行更新的时候会执行。可能会执行多次
    updated:function(){}
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

4、钩子函数

全局自定义指令

Vue.directive("colors",{
    bind:function(el,bingding){
        el.style.color = bingding.value
    }
})
Vue.directive("colors",function(el,bingding){el.style.color = bingding.value})//如果函数只在bind和update中使用的话就可以简写
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • bindi ng:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”。
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”。
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 [dataset](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/dataset) 来进行。

局部自定义指令

directives:{
    "alloproject":{
        bind:function(el,bingding){
            el.style.color = bingding.value
        }
    },
        "stylessss":function(el,bingding){
            el.style.color = bingding.value
        }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

四、Vue实例的生命周期

image-20210118174058871.png

五、动画

具体看官网吧。笔记中基本没有记录

JavaScript 钩子

可以在 attribute 中声明 JavaScript 钩子

<transition v-on:before-enter=“beforeEnter” v-on:enter=“enter” v-on:after-enter=“afterEnter” v-on:enter-cancelled=“enterCancelled”

v-on:before-leave=“beforeLeave” v-on:leave=“leave” v-on:after-leave=“afterLeave” v-on:leave-cancelled=“leaveCancelled”

六、Vue组件

1、定义Vue组件

全局定义组件的三中方式

不管哪种方式创建的组件都只能有一个根,多个根报错

1.使用Vue注册组件

<div id="app">
    <!--这里如果注册的时候使用驼峰命名法就需要加上-不使用驼峰命名法就不用加-->
    <my-com1></my-com1>
</div>
<script>
    //创建组件步骤
    //1.创建一个组件对象
    var com1 = Vue.extend({
        template:"<h1>欢迎来到王者荣耀</h1>"
    })
    //2.注册组件
    Vue.component("myCom1",com1)
    var vm=new Vue({
        el:"#app",
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2.直接创建

<div id="app">
    <!--这里如果注册的时候使用驼峰命名法就需要加上-不使用驼峰命名法就不用加-->
    <my-com1></my-com1>
</div>
<script>
    //创建组件步骤
    //创建组件
    Vue.component("myCom1",{
        template:"<h1>欢迎来到王者荣耀</h1>"
    })
    var vm=new Vue({
        el:"#app",
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3.通过外部模板

<div id="app">
    <template id="temp1">
        <div>
            <h1>Hello world</h1>
        </div>
    </template>
    <!--这里如果注册的时候使用驼峰命名法就需要加上-不使用驼峰命名法就不用加-->
    <my-com1></my-com1>
</div>
<script>
    //创建组件步骤
    //创建组件
    Vue.component("myCom1",{
        template:"#temp1"
    })
    var vm=new Vue({
        el:"#app",
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

局部定义私有组件

三种创建方式和全局一样

<script>
    var vm=new Vue({
        el:"#app",
        components:{
            template:"<h1>hello world</h1>"
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、Vue组件的data

组件中可以定义data,但是和实例中的data有些不同,示例中的data不用函数。组件中必须要用函数,实例中的data没有返回值,组件中的data必须要返回对象 组件中定义的数据只能在组件中使用

<script>
    //创建组件步骤
    //1.创建一个组件对象
    var com1 = Vue.extend({
        template:"<h1>欢迎来到王者荣耀{{msg}}</h1>",
        data:function(){
            return {
                msg:"hello"
            }
        }
    })
    //2.注册组件
    Vue.component("myCom1",com1)


    var vm=new Vue({
        el:"#app",
        data:{

        },
        methods:{
            
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

3、vue组件中的其他方法

组件中可以定义和实例中相同的方法入methods

//创建组件步骤
//1.创建一个组件对象
var com1 = Vue.extend({
    template:"<h1>欢迎来到王者荣耀{{msg}}</h1>",
    data:function(){
        return {
            count: "0"
        }
    },
    methods:{
        incream: function(){
            count ++;
        }
    }
})
//2.注册组件
Vue.component("myCom1",com1)


var vm=new Vue({
    el:"#app",
    data:{

    },

})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

4、组件之间的数值传递

组件之间的数据传递

<body>
  <div id="app">
    <!-- 父组件,可以在引用子组件的时候, 通过 属性绑定(v-bind:) 的形式, 把 需要传递给 子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 -->
    <com1 v-bind:parentmsg="msg"></com1>
  </div>

  <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: "#app",
      data: {
        msg: "123 啊-父组件中的数据",
      },
      methods: {},

      components: {
        // 结论:经过演示,发现,子组件中,默认无法访问到 父组件中的 data 上的数据 和 methods 中的方法
        com1: {
          data() {
            // 注意: 子组件中的 data 数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如: 子组件通过 Ajax ,请求回来的数据,都可以放到 data 身上;
            // data 上的数据,都是可读可写的;
            return {
              title: "123",
              content: "qqq",
            };
          },
          template: '<h1 @click="change">这是子组件 --- {{ parentmsg }}</h1>',
          // 注意: 组件中的 所有 props 中的数据,都是通过 父组件传递给子组件的
          // props 中的数据,都是只读的,无法重新赋值
          props: ["parentmsg"], // 把父组件传递过来的 parentmsg 属性,先在 props 数组中,定义一下,这样,才能使用这个数据
          directives: {},
          filters: {},
          components: {},
          methods: {
            change() {
              this.parentmsg = "被修改了";
            },
          },
        },
      },
    });
  </script>
</body>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

父组件向子组件传递方法

<div id="app">
  <!-- 父组件向子组件 传递 方法,使用的是 事件绑定机制; v-on, 当我们自定义了 一个 事件属性之后,那么,子组件就能够,通过某些方式,来调用 传递进去的 这个 方法了 -->
  <com2 @func="show"></com2>
</div>

<template id="tmpl">
  <div>
    <h1>这是 子组件</h1>
    <input
      type="button"
      value="这是子组件中的按钮 - 点击它,触发 父组件传递过来的 func 方法"
      @click="myclick"
    />
  </div>
</template>

<script>
  // 定义了一个字面量类型的 组件模板对象
  var com2 = {
    template: "#tmpl", // 通过指定了一个 Id, 表示 说,要去加载 这个指定Id的 template 元素中的内容,当作 组件的HTML结构
    data() {
      return {
        sonmsg: { name: "小头儿子", age: 6 },
      };
    },
    methods: {
      myclick() {
        // 当点击子组件的按钮的时候,如何 拿到 父组件传递过来的 func 方法,并调用这个方法???
        //  emit 英文原意: 是触发,调用、发射的意思
        // this.$emit('func123', 123, 456)
        this.$emit("func", this.sonmsg);
      },
    },
  };

  // 创建 Vue 实例,得到 ViewModel
  var vm = new Vue({
    el: "#app",
    data: {
      datamsgFormSon: null,
    },
    methods: {
      show(data) {
        // console.log('调用了父组件身上的 show 方法: --- ' + data)
        // console.log(data);
        this.datamsgFormSon = data;
      },
    },

    components: {
      com2,
      // com2: com2
    },
  });
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

七、Vue 的路由

1、前端路由和后端路由的区别

后端路由就是一套 url 地址,每个页面对应不同的 url 地址 前端路由就是#hash 后的请求是不会相应的,前端路由基于这个进行前端页面的显示控制

2、Vue 路由的安装

3、vue 路由的使用

<div id="app">
  <!-- <a href="#/login">登录</a> -->
  <!-- <a href="#/register">注册</a> -->

  <!-- router-link 默认渲染为一个a 标签 -->
  <router-link to="/login" tag="span">登录</router-link>
  <router-link to="/register">注册</router-link>

  <!-- 这是 vue-router 提供的元素,专门用来 当作占位符的,将来,路由规则,匹配到的组件,就会展示到这个 router-view 中去 -->
  <!-- 所以: 我们可以把 router-view 认为是一个占位符 -->
  <transition mode="out-in">
    <router-view></router-view>
  </transition>
</div>

<script>
  // 组件的模板对象
  var login = {
    template: "<h1>登录组件</h1>",
  };

  var register = {
    template: "<h1>注册组件</h1>",
  };

  /*  Vue.component('login', {
       template: '<h1>登录组件</h1>'
     }) */

  // 2. 创建一个路由对象, 当 导入 vue-router 包之后,在 window 全局对象中,就有了一个 路由的构造函数,叫做 VueRouter
  // 在 new 路由对象的时候,可以为 构造函数,传递一个配置对象
  var routerObj = new VueRouter({
    // route // 这个配置对象中的 route 表示 【路由匹配规则】 的意思
    routes: [
      // 路由匹配规则
      // 每个路由规则,都是一个对象,这个规则对象,身上,有两个必须的属性:
      //  属性1 是 path, 表示监听 哪个路由链接地址;
      //  属性2 是 component, 表示,如果 路由是前面匹配到的 path ,则展示 component 属性对应的那个组件
      // 注意: component 的属性值,必须是一个 组件的模板对象, 不能是 组件的引用名称;
      // { path: '/', component: login },
      { path: "/", redirect: "/login" }, // 这里的 redirect 和 Node 中的 redirect 完全是两码事
      { path: "/login", component: login },
      { path: "/register", component: register },
    ],
    linkActiveClass: "myactive",
  });

  // 创建 Vue 实例,得到 ViewModel
  var vm = new Vue({
    el: "#app",
    data: {},
    methods: {},
    router: routerObj, // 将路由规则对象,注册到 vm 实例上,用来监听 URL 地址的变化,然后展示对应的组件
  });
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

4、路由中传值的两种方式

1.直接在url路径中添加参数

<div id="app">
    <router-link to="/login?id=10&name=zs">登录</router-link>
    <router-link to="/register">注册</router-link>

    <router-view></router-view>
</div>
<script>
    var login = {
        template:"<h1>登录 --- {{$route.query.id}}  --- {{$route.query.name}}</h1>",
        data(){
            return {
                msg:"123"
            }
        },
        created(){
            // console.log(this.$route)
            // console.log(this.$route.query.id)
        }
    }
    
    var register = {
        template: "<h1>注册</h1>"
    }

    var router = new VueRouter({
        routes:[
            {path:"/login",component:login},
            {path:"/register",component:register}
        ]
    })

    var vm=new Vue({
        el:"#app",
        data:{},
        methods:{},
        router
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

2.使用特殊的后缀来添加参数

<div id="app">
    <router-link to="/login/12/ls">登录</router-link>
    <router-link to="/register">注册</router-link>

    <router-view></router-view>
</div>
<script>
    var login = {
        template:"<h1>登录 --- {{$route.params.id}}  --- {{$route.params.name}}</h1>",
        data(){
            return {
                msg:"123"
            }
        },
        created(){
            console.log(this.$route)
            console.log(this.$route.query.id)
        }
    }
    
    var register = {
        template: "<h1>注册</h1>"
    }

    var router = new VueRouter({
        routes:[
            {path:"/login/:id/:name",component:login},
            {path:"/register",component:register}
        ]
    })

    var vm=new Vue({
        el:"#app",
        data:{},
        methods:{},
        router
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

5、vue路由嵌套

<div id="app">
    
    <router-link to="/account"> Account</router-link>
    <router-view></router-view>
</div>


<template id="tmpl">
    <div>
        <h1>这是 Account 组件</h1>

        <router-link to="/account/login">登录</router-link>
        <router-link to="/account/register">注册</router-link>

        <router-view></router-view>
    </div>
</template>
<script>
    var account ={
        template:"#tmpl"
    }

    var login = {
        template : "<h3>登录</h3>"
    }

    var register ={
        template : "<h3>注册</h3>"
    }

    var router= new VueRouter({
        routes:[
            {
                path:'/account',
                component:account,
                children:[
                    {path:'login',component:login},
                    {path:'register',component:register}
                ]
            }
        ]
    })

    var vm=new Vue({
        el:"#app",
        data:{},
        methods:{},
        router
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

6、路由命名视图

<div id="app">
    <router-view></router-view>
    <router-view name = "left"></router-view>
    <router-view name="main"></router-view>
</div>
<script>
    var header = {
    template: '<h1 class="header">Header头部区域</h1>'
    }

    var leftBox = {
    template: '<h1 class="left">Left侧边栏区域</h1>'
    }

    var mainBox = {
    template: '<h1 class="main">mainBox主体区域</h1>'
    }
    var router = new VueRouter({
        routes: [
            /* { path: '/', component: header },
            { path: '/left', component: leftBox },
            { path: '/main', component: mainBox } */
            {
                path: '/', components: {
                    'default': header,
                    'left': leftBox,
                    'main': mainBox
                }
            }
        ]
    })


    var vm=new Vue({
        el:"#app",
        data:{

        },
        methods:{
            
        }
    })
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

webpack的使用

一、项目目录的初始化

1、全局安装webpack

npm i webpack@3.8.1 -g

2、创建目录结构

3、初始化项目

npm init -y

4、安装jquery依赖

不推荐在页面中引用jquery,推荐在main.js文件中添加jquery的引用

npm i jquery -S

5、在webpack中配置要进行打包的文件

import $ from 'jquery'

$(function(){
    $('li:odd').css('backgroundColor','green');
    $('li:even').css('backgroundColor','pink')
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

6、使用webpack-dev-server依赖自动进行webpack打包操作

cnpm i webpack-dev-server@2.9.3 -D

配置package.js中"dev": “webpack-dev-server”

{
  "name": "vue-test",
  "version": "1.0.0",
  "description": "adf",
  "main": "index.js",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "jquery": "^3.5.1",
    "webpack": "^3.8.1",
    "webpack-dev-server": "^2.9.3"
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

7、启动

cnpm run dev

之后就会实时监控对应main.js文件中的变化并事实响应到对应的文件中。

但是修改的问文件是在内存中的,并不是之前使用webpack生成的文件虽然名字一样但是位置不一样。这个内存中的位置在根路径下。

所以需要把js的引用改为/bundle.js才能后看到实时的显示效果

8、配置package.json来控制相关行为

启动后自动打开浏览器

“dev”: “webpack-dev-server --open”

自动打开某个端口

“dev”: “webpack-dev-server --open --port 3000”

自动打开某个路径

“dev”: “webpack-dev-server --open --port 3000 --contentBase src”

另一种配置方式(了解),使用webpack.config.js来配置

// 导入处理路径的模块
const path = require('path');
const webpack = require('webpack');


// 导出一个配置对象,将来webpack在启动的时候,会默认来查找webpack.config.js,并读取这个文件中导出的配置对象,来进行打包处理
module.exports = {
    entry: path.resolve(__dirname, 'src/mian.js'), // 项目入口文件
    output: { // 配置输出选项
        path: path.resolve(__dirname, 'dist'), // 配置输出的路径
        filename: 'bundle.js' // 配置输出的文件名
    },
    devServer: {

        open: true, // 自动打开浏览器
        port: 3000, // 设置启动时候的运行端口
        contentBase: 'src', // 指定托管的根目录
        hot:true
        
    },
    plugins:[
        new webpack.HotModuleReplacementPlugin()// new 一个热更新的 模块对象, 这是 启用热更新的第 3 步HotModuleReplacementPlugin
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

项目中安装的各个软件包的版本

"css-loader": "^0.28.7",
"html-webpack-plugin": "^2.30.1",
"less": "^2.7.3",
"less-loader": "^4.0.5",
"node-sass": "^4.5.3",
"sass-loader": "^6.0.6",
"style-loader": "^0.19.0",
"webpack": "^3.8.1",
"webpack-dev-server": "^2.9.3"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

安装html-webpack-plugin

cnpm i html-webpack-plugin@2.30.1 -D

操作

const htmlWebpackPlugin = require('html-webpack-plugin')

plugins: [ // 配置插件的节点
    new htmlWebpackPlugin({ // 创建一个 在内存中 生成 HTML  页面的插件
        template: path.join(__dirname, './src/index.html'), // 指定 模板页面,将来会根据指定的页面路径,去生成内存中的 页面
        filename: 'index.html' // 指定生成的页面的名称
    })
],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

二、webpack解析其他的类型文件

1、安装插件style-loader css-loader

cnpm i style-loader css-loader -D

2、在webpack.config.js中配置

// 导入处理路径的模块
const path = require('path');
const webpack = require('webpack');
const htmlWebpackPlugin  = require('html-webpack-plugin')
// 导出一个配置对象,将来webpack在启动的时候,会默认来查找webpack.config.js,并读取这个文件中导出的配置对象,来进行打包处理
module.exports = {
    entry: path.resolve(__dirname, 'src/mian.js'), // 项目入口文件
    output: { // 配置输出选项
        path: path.resolve(__dirname, 'dist'), // 配置输出的路径
        filename: 'bundle.js' // 配置输出的文件名
    },
    devServer: {

        open: true, // 自动打开浏览器
        port: 3000, // 设置启动时候的运行端口
        contentBase: 'src', // 指定托管的根目录
        hot:true
        
    },
    plugins:[
        new webpack.HotModuleReplacementPlugin(),// new 一个热更新的 模块对象, 这是 启用热更新的第 3 步HotModuleReplacementPlugin
        new htmlWebpackPlugin({ // 创建一个 在内存中 生成 HTML  页面的插件
            template: path.join(__dirname, './src/index.html'), // 指定 模板页面,将来会根据指定的页面路径,去生成内存中的 页面
            filename: 'index.html' // 指定生成的页面的名称
          })
    ],
    module: { // 这个节点,用于配置 所有 第三方模块 加载器 
        rules: [ // 所有第三方模块的 匹配规则
          { test: /\.css$/, use: ['style-loader', 'css-loader'] }, //  配置处理 .css 文件的第三方loader 规则
        //   { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }, //配置处理 .less 文件的第三方 loader 规则
        //   { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, // 配置处理 .scss 文件的 第三方 loader 规则
        ]
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

const htmlWebpackPlugin = require(‘html-webpack-plugin’)

module: { // 这个节点,用于配置 所有 第三方模块 加载器 rules: [ // 所有第三方模块的 匹配规则 { test: /.css外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传/, use: [‘style-loader’, ‘css-loader’, ‘less-loader’] }, //配置处理 .less 文件的第三方 loader 规则 // { test: /.scss$/, use: [‘style-loader’, ‘css-loader’, ‘sass-loader’] }, // 配置处理 .scss 文件的 第三方 loader 规则 ] }

三、webpack解析Es6高级语法

// 在 webpack 中,默认只能处理 一部分 ES6 的新语法,一些更高级的ES6语法或者 ES7 语法,webpack 是处理不了的;这时候,就需要 借助于第三方的 loader,来帮助webpack 处理这些高级的语法,当第三方loader 把 高级语法转为 低级的语法之后,会把结果交给 webpack 去打包到 bundle.js 中
// 通过 Babel ,可以帮我们将 高级的语法转换为 低级的语法
// 1. 在 webpack 中,可以运行如下两套 命令,安装两套包,去安装 Babel 相关的loader功能:
// 1.1 第一套包: cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
// 1.2 第二套包: cnpm i babel-preset-env babel-preset-stage-0 -D
// 2. 打开 webpack 的配置文件,在 module 节点下的 rules 数组中,添加一个 新的 匹配规则:
// 2.1 { test:/\.js$/, use: 'babel-loader', exclude:/node_modules/ }
// 2.2 注意: 在配置 babel 的 loader规则的时候,必须 把 node_modules 目录,通过 exclude 选项排除掉:原因有俩:
// 2.2.1 如果 不排除 node_modules, 则Babel 会把 node_modules 中所有的 第三方 JS 文件,都打包编译,这样,会非常消耗CPU,同时,打包速度非常慢;
// 2.2.2 哪怕,最终,Babel 把 所有 node_modules 中的JS转换完毕了,但是,项目也无法正常运行!
// 3. 在项目的 根目录中,新建一个 叫做 .babelrc  的Babel 配置文件,这个配置文件,属于JSON格式,所以,在写 .babelrc 配置的时候,必须符合JSON语法规范: 不能写注释,字符串必须用双引号
// 3.1 在 .babelrc 写如下的配置:  大家可以把 preset 翻译成 【语法】 的意思
        // {
        //   "presets": ["env", "stage-0"],
        //   "plugins": ["transform-runtime"]
        // }
// 4. 了解: 目前,我们安装的 babel-preset-env, 是比较新的ES语法, 之前, 我们安装的是 babel-preset-es2015, 现在,出了一个更新的 语法插件,叫做 babel-preset-env ,它包含了 所有的 和 es***相关的语法
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

四、webpack下进行vue的项目搭建

安装vue

cnpm i vue -S

导入vue

// 在webpack 中尝试使用 Vue:
// 注意: 在 webpack 中, 使用 import Vue from 'vue' 导入的 Vue 构造函数,功能不完整,只提供了 runtime-only 的方式,并没有提供 像网页中那样的使用方式;
import Vue from 'vue'
// import Vue from '../node_modules/vue/dist/vue.js'
// 回顾 包的查找规则:
// 1. 找 项目根目录中有没有 node_modules 的文件夹
// 2. 在 node_modules 中 根据包名,找对应的 vue 文件夹
// 3. 在 vue 文件夹中,找 一个叫做 package.json 的包配置文件
// 4. 在 package.json 文件中,查找 一个 main 属性【main属性指定了这个包在被加载时候,的入口文件】
// 当以命令行形式运行 webpack 或 webpack-dev-server 的时候,工具会发现,我们并没有提供 要打包 的文件的 入口 和 出口文件,此时,他会检查项目根目录中的配置文件,并读取这个文件,就拿到了导出的这个 配置对象,然后根据这个对象,进行打包构建
module.exports = {
  entry: path.join(__dirname, './src/main.js'), // 入口文件
  output: { // 指定输出选项
    path: path.join(__dirname, './dist'), // 输出路径
    filename: 'bundle.js' // 指定输出文件的名称
  },
  resolve: {
    alias: { // 修改 Vue 被导入时候的包的路径
      // "vue$": "vue/dist/vue.js"
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

使用webpack解析vue把vue渲染到html中

// 1. 导入 login 组件
import login from './login.vue'
// 默认,webpack 无法打包 .vue 文件,需要安装 相关的loader: 
//  cnpm i vue-loader vue-template-compiler -D
//  在配置文件中,新增loader哦配置项 { test:/\.vue$/, use: 'vue-loader' }
  • 1
  • 2
  • 3
  • 4
  • 5

vue想要渲染出来需要render实例

  // components: {
  //   login
  // }
  /* render: function (createElements) { // 在 webpack 中,如果想要通过 vue, 把一个组件放到页面中去展示,vm 实例中的 render 函数可以实现
    return createElements(login)
  } */

  render: c => c(login)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

ES6语法

es6向外暴露对象和node向外暴露成员比较

pass
  • 1

1、es6 export 和 exports default暴露

// 在 ES6中,也通过 规范的形式,规定了 ES6 中如何 导入 和 导出 模块
//  ES6中导入模块,使用   import 模块名称 from '模块标识符'    import '表示路径'

// 在 ES6 中,使用 export default 和 export 向外暴露成员:
var info = {
  name: 'zs',
  age: 20
}

export default info

/* export default {
  address: '北京'
} */

// 注意: export default 向外暴露的成员,可以使用任意的变量来接收
// 注意: 在一个模块中,export default 只允许向外暴露1次
// 注意: 在一个模块中,可以同时使用 export default 和 export 向外暴露成员



export var title = '小星星'
export var content = '哈哈哈'

// 注意: 使用 export 向外暴露的成员,只能使用 { } 的形式来接收,这种形式,叫做 【按需导出】
// 注意: export 可以向外暴露多个成员, 同时,如果某些成员,我们在 import 的时候,不需要,则可以 不在 {}  中定义
// 注意: 使用 export 导出的成员,必须严格按照 导出时候的名称,来使用  {}  按需接收;
// 注意: 使用 export 导出的成员,如果 就想 换个 名称来接收,可以使用 as 来起别名;



// 这是 Node 中向外暴露成员的形式:
// module.exports = {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

git

1、.gitgnore

git忽略文件夹,所有在里面标注的文件夹都不会上传

2、license

开源协议的文件

开源协议之间的异同点

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/671323
推荐阅读
相关标签
  

闽ICP备14008679号