zoukankan      html  css  js  c++  java
  • Vue个人笔记

    {}相当于new object,
    先把基础的Vue学好,之后再用脚手架,就能够融会贯通了!!!

    vue对象中的几个主要对象:
    new Vue({
        el:'app',           //作用于哪个模板
        data:{}             //存放vue组件的数据
        methods:{}         //dom绑定事件的书写区
        computed:{}        //计算属性,对于任何复杂逻辑,你都应当使用计算属性,里面放的是函数!
        directives: {}       //自定义指令
        components:{}        //自定义组件
    });

    //根组件
    new Vue({
        data:{}             //存放vue组件的数据
        methods:{}         //dom绑定事件的书写区
        computed:{}
        
            //子组件
        component:{
                data:{}             //存放vue组件的数据
            methods:{}         //dom绑定事件的书写区
            computed:{}
        }
    });

    一:页面渲染( Rendering ) 
    1,数据绑定
        数据绑定最常见的形式就是使用“ Mustache” 语法 ( 双大括号 ) 的文本插值
        {{msg}}
        可以在双大括号中使用 Javascript 表达式
        {{ message.split('').reverse().join('') }}
    2,计算属性
    模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的
    逻辑会让模板过重且难以维护。
        <div id="example">{{ message.split('').reverse().join('') }}</div>
        对于任何复杂逻辑,你都应当使用计算属性
        <div id="example">
            <p>Computed reversed message: "{{ reversedMessage }}"</p>
        </div>
        var app = new Vue({
            el: '#example',data: {message: 'Hello'},
            computed: {
            reversedMessage: function ()
            {
                    return this.message.split('').reverse().join('')
            }
        }})
    3,属性的绑定
    指令 (Directives) 是带有 v- 前缀的特殊属性,指令的职责是,当表达式的值改变时,将
    其产生的连带影响,响应式地作用于 DOM 。一些指令能够接收一个“ ” 参数 ,在指令名称
    之后以冒号表示。

    v-bind 指令可以用于响应式地更新 HTML 属性,简写形式为 ":"
    <a v-bind:href="url"></a>

    4,事件的绑定
    v-on 指令用于监听 DOM 事件,参数为事件名称,引号内为绑定的事件处理函数或者是
    Javascript 代码(不推荐)。简写形式为 "@"
    <a v-on:click="doSomething"></a>

    4-2
    事件修饰符
    <form v-on:submit.prevent="onSubmit"></form>
    类似的还有停止冒泡( .stop ) , 只当事件在当前元素本身时触发( .self ),仅触发一次 事件( .once )
    键值修饰符
    <input v-on:keyup.13=“submit”> 13 可以使用 .submit 代替
    .enter 、 .tab 、 .delete 、 .esc 、 .space 、 .up 、 .down 、 .left 、 .right

    5,条件渲染( v-if )
        根据给定条件判断决定是否显示元素
        <h1 v-if="type === 'A'">A</h1>
        <h1 v-else-if="type === 'B'">B</h1>
        <h1 v-else>C</h1>
    条件渲染( v-show )
        与 v-if 不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。 v-show 是简单地切换元素的 CSS 属性 display
        注意, v-show 不支持 <template> 语法,也不支持 v-else 。 如果需要非常频繁地切换元素,则使用 v-show 较好

    6, 列表渲染( v-for )
    v-for 指令根据一组数组的选项列表进行渲染,使用 item in items 形式的特殊语法
     items 是源数据数组并且 item 是数组元素迭代的别名

    7,表单输入绑定
    v-model 指令可以在表单控件元素上创建双向数据绑定(不会用于文本元素)
        1 . 单行文本、多行文本框、单选按钮、下拉菜单简单使用 v-model 绑定即可
        <input v-model="message"><p>Message is: {{ message }}</p>
        2 . 复选框(绑定到一个数组中)
        <input type="checkbox" value="Jack" v-model="checkedNames">
        <input type="checkbox" value="Jack" v-model="checkedNames">
        data:{checkedNames:[]}

    二:动画(animation)

    Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。 包括以下工具:
    1,在 CSS 过渡和动画中自动应用 class
    2,可以配合使用第三方 CSS 动画库,如 Animate.css
    3,在过渡钩子函数中使用 JavaScript 直接操作 DOM
    4,可以配合使用第三方 JavaScript 动画库,如 Velocity.js
    Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添 加 entering/leaving 过渡
    在进入 / 离开的过渡中,会有 6 个 class 切换, v- 是这些类名的前缀,可以在transition 标签中设定 name 属性改变该前缀。
    v-enter(进入前) v-enter-active(进入中) v-enter-to(进入后)   v-leave(离开前)  v-leave-active(离开中)  v-leave-to(离开后)
    1,自定义过渡样式
            <button @click='show = !show'> 切换 </button>
                <transition name='fade'>
                    <p v-if='show'> hello vue </p>
                </transition>
            <style>
                .fade-enter-active, .fade-leave-active {
                    transition: opacity .5s
                }
                .fade-enter, .fade-leave-to {
                    opacity: 0
                }
            </style>
            
    2,自定义过渡的类名,和其他第三方动画库,animate.css结合使用
    enter-class 、 enter-active-class 、 enter-to-class
    leave-class 、 leave-active-class 、 leave-to-class

        <link rel="stylesheet" href="../css/animate.css">
            <button @click='show = !show'> 切换 </button>
        <transition
            enter-active-class='animated bounce'
            leave-active-class='animated bounce'>
            <p v-if='show'> hello vue </p>
        </transition>

    3,javascript 钩子,可以通过 js 钩子定义动画,结合第三方动画库 Velocity.js( 以及插件Velocity.ui.js)
    before-enter 、 enter 、 after-enter 、 before-leave 、 leave 、 after-leave
        <script src="../js/velocity.min.js"></script>
        <script src="../js/velocity.ui.js"></script>
            <button @click='show = !show'> 切换 </button>
            <transition @enter='enter' @leave='leave'>
                <p v-if='show'> hello vue </p>
            </transition>
        methods:{
            enter:function(el,done){
            Velocity(el,"callout.pulse", { duration: 650 ,complete:done}) },
            leave:function(el,done){
            Velocity(el,"callout.bounce", { duration: 1500 ,complete:done}) }
        }
        
    4,列表过渡
        为了同时渲染整个列表,使用 <transition-group> ,不同于 <transition> ,它会
        以一个真实元素呈现:默认为一个 <span> 。你也可以通过 tag 特性更换为其
        他元素,内部元素 总是需要 提供唯一的 key 属性值
        <script src="../js/velocity.min.js"></script>
        <transition-group tag="ul" @enter="enter" @leave="leave" >
            <li v-for='name in nameList' :key='name'>{{name}}</li>
        </transition-group>
        methods:{
            enter:function(el,done){
            Velocity(el,{ opacity: 1, height: '1.6em' },{ complete: done })},
            leave:function(el,done){
            Velocity(el,{ opacity: 0, height: 0 },{ complete: done })}
        }
        
    三:组件
    组件 (Component) 是 Vue.js 最强大的功能之一。在较高层面上,组件是自定义元素,template用反引号``, 比用引号方便

    1,全局注册
        Vue.component('my-component', {
            // 构造 Vue 实例时传入的选项大多数都可以在组件里使用。 data 为函数
            template : '<div>A custom component!</div>'
        })
        组件在注册之后,便可以作为自定义元素 <my-component></my-component> 在一个实例的模板中使用。注意确保在初始化根实例之前注册
    组件(即 new Vue({}))

    2,局部注册
    局部注册 不必把每个组件都注册到全局。我们可以通过某个 Vue 实例 / 组件的实例
    选择 components 注册仅在其作用域中可用的组件。
        var app = new Vue({
            el:'#app',
            components:{
                'my-component':{ template:'<h2>hello component</h2>'}
            }
        });

    3,自定义组件的使用
            1,直接使用
                <my-row></my-row>
          2,通过 is 关键字使用
        第一种方式会受到 HTML 本身的限制,因为 Vue 只有在浏览器解析、规范化模
        板之后才能获取其内容,像 <ul> 、 <ol> 、 <table> 、 <select> 这样的元素里允
        许包含的元素有限制。
        <table>
            <my-row></my-row>
        </table>
        变通方法:
        <table>
            <tr is="my-row"></tr>
        </table>

    4,父子组件通信
    在 Vue 中,父子组件的关系可以总结为 prop 向下(子)传递,事件向上(父)传递 。
    父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息

        1,父子组件 -props
            子组件要显式地用 props 选项声明它预期的数据,父组件使用 props 中声明
            的同名属性进行注入
            var app = new Vue({
                el:'#app',
                data:{name:'hello parent'},
                components:{
                    'my-son':{
                    props:['name'],// 不区分大小写
                    data:function(){return {msg:'hello son' }},
                    template:'<div> 子组件, {{msg}},{{name}}</div>'
                    }
                }
            });
            <div id="app"><my-son :name='name'></my-son></div>
            
        2,父子组件 - 自定义事件
        子组件使用自定义事件系统与父组件通信,每个 Vue 实例都实现了事件接口,使用 $on(eventName) 监听事件,
        使用 $emit(eventName) 触发事件 。父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件
        <div id="app">
            <p><b>total:</b>{{total}}</p>
            <button-counter @increment='incrementTotal'></button-counter>     //监听
            <button-counter @increment=‘incrementTotal’></button-counter>
            </div>
            components:{
                'button-counter':{
                ‘template’:‘<button @click=“incrementCounter”>{{counter}}</button>’,
                data:function(){ return {counter:0}},
                methods:{
                incrementCounter:function(){
                this.counter++;
                this.$emit('increment'); // 向父组件发射事件
            }
            } }
            
        3,插槽
        要想在子组件中使用父组件提供的模板就需要使用到插槽。除非子组件模板包含至少一个 <slot> 插口,否则父组件的内容将会被丢弃。
        <div id="app">
            <my-component><h3>hello Vue</h3></my-component>
        </div>
        components:{
            'my-component':{
            template:'<div><h2>hello my-component</h2><slot>default slot</slot></div>'
            }
        }
        也可以为插槽提供名字,这样可以在一个子组件中插入多个父组件提供的模板。
        <slot name="header"></slot>
        <slot name="footer"></slot>
        <h1 slot="header"> 这里可能是一个页面标题 </h1>
        <p slot="footer"> 这里有一些联系信息 </p>
        
        4,作用域插槽
    作用域插槽是一种特殊类型的插槽,用作一个 ( 能被传递数据的 ) 可重用模板,来代替已经渲染好的元素。
    在子组件中,只需将数据传递到插槽,在组件中,具有特殊特性 slot-scope 的 <template> 元素必须存在,
    表示它是作用域插槽的模板。
        Vue.component('my-ul',{
            template:‘<ul><slot v-for=“name in names”
            :text="name"></slot></ul>',
            data:function(){return {names:['terry','larry','tom','jacky']}}
        });
        Vue.component('my-list',{
            // 允许使用者自定义如何渲染列表的每一项
            template:‘<my-ul><template slot-scope=“props” >
            <li>{{props.text}}</li></template></my-ul>'
        });
        <div id=’app’>
            <my-list></my-list>
        </div>
        
    5,动态组件---可以用vue插件--路由来代替
    通过使用保留的 <component> 元素,动态地绑定到它的 is 特性,可以让 多个组件可以使用同一个挂载点,并动态切换。
        new Vue({
            data:{ currentView:'my-com2' },
            components:{
                'my-com1':{ template:'<div>component1</div>' },
                'my-com2':{ template:'<div>component2</div>' },
                'my-com3':{ template:'<div>component3</div>' }
            }
        })
        <component v-bind:is="currentView"></component>
        


    学习组件后的总结:
      vue就相当于一个组件,它作用于 el:#app 这个模板,这个模板里的方法,写在methods对象中,模板里的数据写在data对象中.....
        一个组件是一个作用域,它们各自的方法,数据写在相应的组件里。
        template模板中,一定要用一个根标签包裹!

    四:其他

    1,自定义指令
        全局注册
            vue.directive(directiveName,options)
        局部注册
            new Vue({
            directives: {
            directiveName:options
            }
            });
        指令定义函数提供了几个钩子函数:
            bind 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
            inserted 被绑定元素插入父节点时调用
            
        钩子函数参数
            el 指令所绑定的元素,可以用来直接操作 DOM
            binding 一个对象,包含了指令相关的信息(参数 binding.argument )

    2,过滤器
    Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两
    个地方: mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达
    式的尾部,由“ |” 管道 符指示。
        <div id="app"> {{msg | toUpper(arg1,arg2)}}</div>
        new Vue({
            el:"#app",
            data:{msg:'hello world' },
            filters:{
                toUpper:function(val,arg1,arg2){return val.toUpperCase();}
            }
        });

    3,插件的使用
        1,通过 script 标签导入,则不需要
        2,npm,如果在一个模块化工程中使用它,必须要通过 Vue.use() 明确地安装该功能
        var Vue = require('vue')
        var VueRouter = require('vue-router')
        // 不要忘了调用此方法
        Vue.use(VueRouter)
        
        
    VUEX:
    特点:将组件的数据进行集中化管理,将数据以及数据相关操作抽离出来进行统一管理
            只有mutations可以修改state的值(虽然actions也可以,但是不要这样做)
            
    1,state,mutations,actions作用
        <script>
                var store = new Vuex.Store({
                    //保存所有的数据
                    state:{
                        number:0
                    },
                    //突变,用于修改state的值  必须是同步
                    mutations:{
                        updateNumber:function(state,value){
                            state.number = value;
                        }
                    },
                    //动作,用于调用突变,执行数据的改变  context即store存贮对象 ,可以包含任意异步操作
                    actions:{
                        increment:function(context){
                            var value = context.state.number+2;
                            context.commit('updateNumber',value);
                        },
                        decrease:function(context){
                            var value = context.state.number-2;
                            context.commit('updateNumber',value);
                        }
                    }
                });
                new Vue({
                    el:'#app',
                    store:store,
                    //用computed计算传值
                    computed:{
                        ...Vuex.mapState(['number'])
                    },
                    methods:{
                        ...Vuex.mapActions(['increment','decrease'])
                    }
                });
            </script>
            
    2,vue组件怎么访问到state中的数据
        
        通过在根实例中注册 store 选项,该 store 实例会注入到根组件
        下的所有子组件中,且子组件能通过 this.$store 访问到。
        new Vue({
        el:'#app',
        store:store,
        computed: {count () {return this.$store.state.count}}
        })
        
        2-1访问简化方式:
                --------
                <div>{{num}}---{{name}}</div>
        
                --------
                state:{
                    number:0,
                    name:'kb'
                }
                --------
            computed:{
                    //div显示的值要和state的值一致
                    // ...Vuex.mapState(['number','name'])
                    //若不一致,可用如下方法
                    ...Vuex.mapState({'num':'number','name':'name'})
                }
                
    3,    定义 Getter
        当我们要过滤从state获取到的数据,可以在 store 中定义“ getter” (可以认为是 store 的计算属性)

            3-1mapGetters 辅助函数
            getters:{
                    boys:function(state){
                        return state.students.filter(
                            function(item){
                                return item.gender == 'male'
                            }
                        )
                    }
                }
            ...Vuex.mapGetters(['boys'])
             //若不一致,可用如下方法
            //...Vuex.mapGetters({'boys2':'boys'})

    4,怎么在vue中调用mutations方法(使用commit)
        更改 Vuex 的 store 中的状态的唯一方法是提交 mutation ,必须是同步操作。
        4-1,提交载荷( 就是传参的意思 )
        mutations:{
                        add:function(state,e){
                                state.events.push(e)
                        }
                }    
        ----------------    
        methods{
        方法1:    this.$store.commit('add',Object.assign({},this.form));  
                //Object.assign({目标对象},{源对象}),Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
                如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
        }
        方法2:
                ...Vuex.mapMutations({add:‘increment'}) // 将 `this.add()` 映射为 `this.$store.commit('increment')`
                this.add(param);
                
    5,怎么在vue中调用Actions方法(使用dispatch方法)
    Action 类似于 mutation ,不同在于, Action 提交的对象的是 mutation ,而不是直接变更状
    态,并且 Action 可以包含任意异步操作, Action 函数接受一个与 store 实例具有相同
    方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation ,或
    者通过 context.state 和 context.getters 来获取 state 和 getters 。
        -------------
            
        methods:{
            //方法1:this.$store.dispatch('increment',{amount:10})
            方法2:...Vuex.mapActions(['increment'])
            this.increament();//直接执行actions中的increment方法    方法2
        }

    什么时候需要承诺?当调用者需要知道这个异步操作执行成功与否的时候!    
    6,当A调用B,A需要当B成功后执行一段代码,失败后执行一段代码(或者需要等B返回一个结果),而B是异步操作,怎么做?(eg:调用删除方法,等待方法返回结果,但是是异步的,没法等)
        在B中使用Promise方法,当B执行成功或失败后,会执行相应的成功,失败方法
        deleteBatch:function(context,ids){
                     //promise用于返回状态给调用者的!!!
                     return new Promise(function(resolve,reject){
                            //$.ajax()......
                            $.ajax({
                            type: "GET",
                            url: 'http://localhost:8080/hello4',
                            success: function (data) {
                                console.log("访问成功");
                                // alert(data);
                                 //刷新,当删除成功后重新执行查询操作
                                context.dispatch('findAll');
                                resolve('success');            //成功执行该方法
                            },
                            error:function (data) {
                                console.log("访问失败");
                                reject(data);                //失败执行该方法
                            }
                        });
                       
                     });

        }
        --------------------
        methods: {
                    handleDelete:function(index,row){
                        this.deleteBatch(row.age).then(function(msg){alert(msg)}).catch(function(e){alert(e)})
                        //当访问的函数返回Promise对象是,可以用.then(成功执行).catch(失败执行)
                    }
        }
        

    webpack结合Vue:
        webpack作用:将模块打包,简化前端开发,导入模块用import,再不用script,link引入js,css了。css,js,图片都写在src目录下,因为
                        一切皆模块,dist存放打包后的文件

     1,本地安装
        npm install –-save-dev webpack
        
     2,使用方式
       初始化项目并安装 webpack
       npm init –y
       npm install --save-dev webpack
     2-1, 编写配置文件 webpack.config.js  (放在项目目录下)
     ——
     module.exports = {
            entry: './src/app.js',        //打包入口文件(从哪开始打包!)
            output:{                    //打包输出目录
                path: __dirname+'/dist',   //—__dirname:代表本文件目录的绝对路径
                filename:'app.bundle.js'    //表示打包后文件名
            }
    };
    使用 npm 脚本执行打包操作 在package.json中添加
    "scripts": { "build": "webpack" }       //npm run build 就可以打包项目了

    以上为webpack环境的搭建!!!


    Loader:加载器(将其他类型的文件加载成可打包类型,css,png...)
        
    3,如何将es6代码打包成es5代码,需要通过babel(浏览器默认是不支持es6的,除了火狐可以解析)
      3-1,安装命令 npm install --save-dev babel-core babel-preset-env babel-loader  //babel一系列东东
      //配置
      3-2,需要在项目目录下新建一个.babelrc文件
        {
        "presets":["env"]
        }
      3-3,在webpack.config.js文件内的module 添加{ test:/.js$/, exclude: /node_modules/, use: 'babel-loader' }
      3-4,
      安装过程可能遇到的错误:
        1,    "babel-core": "^6.26.3"和"babel-loader": "^7.1.5"版本不兼容,按照报错提示再次安装即可
        2,webpack.config.js文件的module属性配置不对,可以按照官网的方法配置!(即rules,不用loaders)

    4,如何将css也弄成模块化(webpack默认只将js文件模块化,图片,css等等得安装loader才可以模块化)
        4-1  安装npm install --save-dev css-loader style-loader
        4-2  配置:在webpack.config.js文件内的module 添加{ test: /.css$/, use: [
                        {loader: 'style-loader' },
                        { loader: 'css-loader'}
                    ]}
        4-3    使用:在入口文件中import './css/style.css';
        
    5,如何将图片模块化,安装loader
        5-1    安装 npm install --save-dev file-loader
        5-2 配置 {test:/.(jpg|png|gif)$/,use:'file-loader'}
        
        
    插件:插件目的在于解决 loader 无法实现的其他事。(前端优化可以想这一点)
    1,压缩插件,为了最小化压缩后的代码,提高加载速度
    2,webpack4已经升级不支持在plugins里面进行操作,而是放在了optimization里面
    3,先安装这个插件 npm install --save-dev uglifyjs-webpack-plugin
    4,配置 :在webpack.config.js
        var UglifyJsPlugin = require('uglifyjs-webpack-plugin');
        optimization: {
                minimizer: [
                    new UglifyJsPlugin({
                        uglifyOptions: {
                            output: { comments: false, } //去除注释
                        }
                    })
                ]
            }

    5,定位错误插件
    module.exports = {
        devtool: 'eval-source-map'
    }

    6,webpack-dev-server
            webpack-dev-server 是一个简单的 web 服务器,在代码修改后能重新构建代码并且
            刷新浏览器。
        //安装    npm install --save-dev webpack-dev-server
        //配置    module.exports = {
                    devServer: {
                    contentBase: './dist' // 服务器服务目录
                    }
                }
                //配置 package.json
                "scripts":{"start": "webpack-dev-server --open"}
                
                

    利用 vue 脚脚手架开发 手架开发企企业级应 业级应用
        # 全局安装 vue-cli
         npm install --global vue-cli
        # 创建一个基于 webpack 模板的新项目
         vue init webpack my-project
        # 安装依赖,走你
         cd my-project
         npm install
         npm run start
        
        安装会出现如下选项,如下选择即可:
        ? Project name app03
        ? Project description sc html
        ? Author kuangbin <981393967@qq.com>
        ? Vue build standalone
        ? Install vue-router? Yes
        ? Use ESLint to lint your code? No
        ? Set up unit tests No
        ? Setup e2e tests with Nightwatch? No

        node_modules文件夹有什么用:
            首先要说明,devDependencies与Dependencies都是依赖。你用npm install就会把里面二者所有的模块都安装到node_modules。
            那为什么还要个devDependencies呢,这里,devDependencies一般用来放一些对项目运行无用,但能帮助开发的依赖(如测试模块),在实际生产环境中执行npm install --production就只安装Dependencies里的模块,而不会安装devDependencies的模块。

        编写项目所需的其它依赖:
        npm install element-ui jquery vuex moment(日期格式处理)--save    //--save才会保留在package.json中

    结合vuex:
        默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
        state模块化他不会为全局声明的,其余是全局声明。
        可以调用getter方法,而不直接调用state获取数据(要用命名空间才可以),但是要避免方法名重复!!!,因为都当做全局声明。

    App.vue 主视图
    index.html 是我们的首页

    如何写一个登陆页面以及结合增删改查?
    1,app.vue不用动,它包含公共部分,然后添加其他组件,放在这个公共app.vue即可,只需用<router-view/>
    2,在router js文件中写上对应的路由映射,记住子路由可以嵌套!
    3,写增删改查页面体悟:只需一个saveOrUpdate方法即可,模态框能重复利用就不用重复写!
    4,登陆之后应该把登陆数据放在store(公共)中,index页面就根据store的数据进行对应登入者展示
    5,注册思想也一致
    6,注意后台传null给前台的话,是转化为"空"字符串,因为家里responseBody!(以后判断为:data!=null&&data!=""就不会错)

  • 相关阅读:
    alpha冲刺—Day5
    alpha冲刺—Day4
    alpha冲刺—Day3
    alpha冲刺—Day2
    alpha冲刺—Day1
    团队作业第五次—alpha冲刺博客汇总
    团队作业第四次—项目系统设计与数据库设计
    团队作业第三次—项目需求分析
    团队作业第二次—团队Github实战训练
    win10配置java环境变量,解决javac不是内部或外部命令等问题
  • 原文地址:https://www.cnblogs.com/wskb/p/11490835.html
Copyright © 2011-2022 走看看