zoukankan      html  css  js  c++  java
  • VueJS 基础知识及项目总结

    1、build :dev-server.js 是在使用终端命令时启动时执行的,里面可以修改端口号 (修改第16行即可)

    2、index.html 是整个文件的入口

      src 装的是你写入的文件
    3、main.js 是当前文件的主要的逻辑入口

       APP.vue 是根组件

    4、一些事件和方法

    v-on:click="事件名"
    v-on:keyup="事件名" //在按下任意键时触发
    v-on:keyup.enter="事件名" // 在按下enter 键时触发
    v-on:keyup.alt.enter="事件名" // 需要按住alt键再按下enter键才会被调用

    更多事件可以去官方文档查看

    5、
    <li v-for="user in users">
    <input type="checkbox" class="toggle"
    v-model="user.contacted"
    >
    <!--下面span中 :class是绑定一个样式,user.contacted为true 时有这个样式,为false时,没有这个样式-->
    <span :class="{contacted:user.contacted}">
    {{user.name}}:{{user.email}}
    <button v-on:click="deleteUser(user)">x</button>
    </span>

    </li>

    6、如何使用路由

    修改了main.js
    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import App from './App'
    import Users from './components/Users'
    import Test from './components/Test'

    Vue.use(VueRouter)

    Vue.config.productionTip = false
    //设置路由
    const router = new VueRouter({
    mode:'history',
    base:__dirname,
    routes:[
    {path:"/",component:Users},
    {path:"/test",component:Test},
    ]
    })
    /* eslint-disable no-new */
    new Vue({
    router,
    template: `
    <div id="app">
    <ul>
    <li>
    <router-link to="/">Users</router-link>
    <router-link to="/test">Test</router-link>
    </li>
    </ul>
    <router-view></router-view>
    </div>
    `
    }).$mount("#app")

    7、如何使用http 请求

    安装 resource npm install vue-resource --save

    jsonplaceholder.typicode.com 中有一些写好的数据

    created 方法不需要调用自动执行


    8、核心概念

    vue:组件化 双向数据流(基于ES5中的defineProperty 来实现的),IE9+才支持

    angular:模块化 双向数据绑定 (脏检测:一个数组($watch))

    在 vue 官网上有vue与其他框架的对比(建议学完vue 再看)


    双向数据流:
    1向 :js 内存属性发生改变,影响页面的变化

    1向 : 页面的改变影响js内存属性的改变


    9、常用指令

    v-text 是元素的innerText 只能在双标签中使用

    v-html 是元素的innerHTML,不能包含{{xxx}}

    v-if 元素是否移除或者插入

    v-show 元素是否显示或隐藏

    v-model 双向数据绑定

    v-bind:value :给value 赋值 v-bind是单向数据绑定(内存js 改变影响页面)

    创建一个项目基本步骤:

    1、创建 index.html

    创建div 标签,id=“App”

    2、配置main.js

    1)引入vue
    2)引入 app.vue,用它的内容来替换 div id = app
    3) 构建 vue 实例

    new Vue({

    //渲染内容的目的地

    el:'#app',

    //渲染内容

    render:function(c){ // c只是一个形参,叫什么都可以
    return c(App)

    }

    })

    //一般来说,key是固定的,值是你设置的(可变的)

    3、app.vue

    里面可以写代码在浏览器中显示了

    <template></template>
    <script></script>
    <style></style>


    10、class 结合v-bind 使用

    需要根据可变的表达式的结果来给class 赋值,就需要用到v-bind:class="xxx"
    v-bind:属性名="表达式",最终表达式运算结束的结果赋值给该属性名

    ——简化的写法是:`:属性名="表达式"`
    class:结果的分类:
    ——一个样式:返回字符串(三元表达式和key和样式的清单对象)
    ——多个样式:返回对象(样式做key,true 或false做值)

    箭头函数:(c)=>{return c(App)}

    1、参数是一个的时候,小括号可以省略
    2、当代码只有一行且是返回值的时候,可以省略大括号
    上述箭头函数简写为 c = > c(App)

    v-bind:class="isRed?'red':'green'" 三元表达式来取其一 取一个,返回一个字符串

    取多个 返回一个对象


    复杂情况,通过遍历,根据当前对象的成绩,匹配成绩和样式
    的清单对象,用成绩做key,取对象的value,最终返回字符串做样式名
    :class="{'A':'red','B':'green'}"[stu.score]
    这里stu.score 为key,通过score去取对象中的值

    11、methods 和 v-on 的使用

    *绑定事件的方法
    `v-on 事件名="表达式||函数名"` 比如:v-on:click="change()"
    简写:`@事件名="表达式||函数名"`

    * 函数名如果没有参数,可以省略() 只给一个函数名称 ,比如 v-on:click="change"

    *声明组件内的函数,在export default 这个对象的根属性加上methods属性,其是一个对象,

    ——key 是函数名,值是函数体
    *在export default 这个对象的根属性加上data属性,其是一个函数,返回一个对象
    ——对象的属性是我们初始化的变量的名称

    *凡是在 template 中使用变量或者函数,不需要加 this,在script中使用就需要加上this

    12、v-for 的使用

    * 可以使用操作数组(item,index)
    * 可以使用操作对象(value,key,index)
    * key是类似trank by 的一个属性
    * 为的是告诉vue ,js 中的元素,与页面之间的关联,当试图删除元素的时候,是单个元素的删除而不是整版替换,所以需要关联其关系,设置(必须,性能) 2.xxx之后必须设置


    13、漂亮的列表

    *绑定class,根据成绩级别显示不同的 class
    :class="{'A':'red','B':'green','C':'blue','D':'pink','E':'gray'}[hero.score]"

    *列表的添加和删除功能
    添加: 通过点击事件向数组中push对象
    删除:根据v-for 中的index ,将被点击的某条删除


    14、父子组件

    在 vue文件中的style 中填写的样式默认是全局的,如果想要局部有效,在style 标签上加上 scoped 字样

    *父和子,使用的是父,被用的是子
    *父需要声明子组件,引入子组件对象,声明方式如下
    ```javascript
    import 组件对象 from './xxx.vue'
    export default{
    components:{
    组件名:子组件对象
    }
    }
    *全局组件,使用更为方便,不需要声明,直接用
    *在main.js 中引入一次,使用`vue.component('组件名','组件对象')`
    *所有的组件就可以直接通过组件名使用
    Vue.component('headerVue',headerVue);//注册一个组件,第一个参数是名称,第二个参数是实际的对象
    // (显示什么内容,具备什么功能)

    15、父组件传递值给子组件

    * 父组件通过子组件的属性将值进行传递
    ——方式有2:常量: prop1="常量值"
    变量: prop2="变量名"
    子组件需要声明
    - 根属性props:['prop1','prop2']
    - 在页面中直接使用{{prop1}}
    - 在js中应该如何使用prop1? 通过 this.prop1 获取

    16、子组件向父组件通信(vuebus)扩展

    通过new Vue()这样的一个对象,来$on('事件名',fn(prop1,prop2))
    另一个组件引入同一个vuebus,来$emit('事件名',prop1,prop2)

    创建通信的js文件,代码为
    import Vue from 'vue';
    var connector = new Vue();
    export default connector;

    父组件中template部分代码:
    <sub-vue></sub-vue>
    <button @click="listen">爸爸焦急的听电话</button>

    script中的部分代码:

    import connect from './connector.js';
    methods:{
    listen(){
    connect.$on('phone',function(msg){
    console.log(msg);
    })
    }
    }
    子组件中template 部分代码:
    <button @click="callDaddy">打电话给爸爸</button>

    script 中的部分代码:
    methods:{
    callDaddy(){
    // 发射信号
    connect.$emit('phone','62分钟来')
    }
    }

    17、vue.js 文档分类
    1、全局的代表Vue.的
    2、实例的代表this. 或者 new Vue().
    3、选项代表 new Vue()的参数或者export default 里边的属性
    全局:通过vue 调用 分 API 和 配置

    全局配置
    silent
    optionMergeStrategies
    devtools
    errorHandler
    warnHandler
    ignoredElements
    keyCodes
    performance
    productionTip

    全局 API
    Vue.extend
    Vue.nextTick
    Vue.set
    Vue.delete
    Vue.directive
    Vue.filter
    Vue.component
    Vue.use
    Vue.mixin
    Vue.compile
    Vue.version

    选项 / 数据 options/类别
    data
    props
    propsData
    computed
    methods
    watch
    选项 / DOM options
    el
    template
    render
    renderError
    选项 / 资源 options
    directives
    filters
    components

    以上带选项的都与实例相关,如:

    new Vue({
    el:
    render:
    })
    export default{
    components:{},
    methods:{

    }
    }

    实例:组件内的this 和 new Vue()

    实例方法 / 事件
    vm.$on
    vm.$once 只触发一次
    vm.$off 取消事件
    vm.$emit

    指令
    v-text
    v-html
    v-show
    v-if
    v-else
    v-else-if
    v-for
    v-on
    v-bind
    v-model
    v-pre
    v-cloak
    v-once

    18、复习

    * vue 单文件方式 xxx.vue
    *1:准备好配置文件 package.json (包描述文件&&封装命令npm run dev)+webpack.config.js文件(打包的配置文件)
    *2:创建index.html(单页应用的页)
    *3:创建main.js(入口文件)
    *4:引入vue和相关的文件 xxx.vue
    *5:new Vue(options)
    *6:options:
    -data
    -methods
    -components(组内声明子组件)
    -props
    *7:实例
    -在组件内(xxx.vue)中的this
    -new Vue()
    -事件
    +this.$on(事件名,回调函数(参数))
    +this.$emit(事件名,数据)
    +this.$once(事件名,回调函数(参数)) 就触发一次
    +this.$off(事件名);取消事件
    *8:全局
    -Vue.component('组件名',组件对象) 在哪里都可以使用

    *9:组件传值
    -父传子:属性作为参数
    +常量 title='xxx'子组件声明接收参数 props:['xxx']
    +变量 v-bind:title='num' 子组件声明接收参数props:['xxx']
    -子传父:vuebus(只能是同一辆车,即事件名相同)
    + 先停车到父组件,on一下
    + 再开车到子组件,如果需要的话,emit一下,触发上述时间的回调函数


    19、过滤器

    *content | 过滤器,vue中没有提供相关的内置过滤器,可以自定义过滤器
    *组件内的过滤器 + 全局过滤器

    -组件内过滤器就是options中的一个filters 的属性(一个对象)+多个key 就是不同过滤器名,多个value就是与key 对应的过滤方式函数体

    -全局过滤器就是Vue.filter(名,fn)

    *输入的内容帮我做一个反转
    当全局过滤器和组件内过滤器重名时,以组件内过滤器为有效

    总结:
    -全局: 范围大,如果出现同名时,权利小
    -组件内:如果出现同名时,权力大,范围小

    20、获取DOM 元素

    *救命稻草,前端框架就是为了减少DOM操作,但是特定情况下,也留了后门。
    *在指定的元素上,添加 ref ='名称'
    *在获取的地方加入 this.$refs.名称A
    -如果ref放在了原生DOM元素上,获取的数据就是原生DOM对象
    + 可以直接操作
    -如果ref放在了组件对象上,获取的就是组件对象,进行操作
    -对应的事件
    +created 完成了数据的初始化,此时还未生成DOM,无法操作DOM
    +mounted 将数据已经装载到了DOM之上,可以操作DOM

    *两个钩子函数 created and mounted (也可以叫事件)
    // 组件创建后,数据已经完成初始化,但是DOM还未生成
    created(){//事件的处理函数(created)
    console.log('created:',this.$refs.myDiv);//获取不到
    },
    // 数据装载到DOM后,各种数据已经就位,将数据渲染到DOM上,DOM已经生成
    mounted(){
    //console.log(this);
    console.log('sub:',this.$refs.sub.$el);
    // 获取组件对象,并获取到其的DOM对象
    this.$refs.sub.$el.innerHTML = "你好";
    // console.log('mounted',this.$refs.myDiv);
    //涉及DOM类的操作
    //this.$refs.myDiv.innerHTML="123456789"
    // 涉及到数据的操作
    this.text="嘻嘻哈哈";
    }

    21、mint-ui

    *饿了么,element-ui 在PC端使用的
    *移动端版本 mint-ui
    *https://mint-ui.github.io/#!/zh-cn
    安装 mint-ui命令:npm i mint-ui -S

    注意:项目中应该按需引入

    //引入全部组件
    import Vue from 'vue';
    import Mint from 'mint-ui';
    Vue.use(Mint);

    //按需引入部分组件
    import { Cell,Checklist } from 'minu-ui';
    Vue.component(Cell.name,Cell);
    Vue.component(Checklist.name,Checklist);

    meta:vp 回车,可以出来meta的完整适配代码:

    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

    注意:
    - 如果是全部安装的方式
    + 1:在template中可以直接使用组件标签 +2:在script中必须要声明,也就是引入组件对象(按需加载)

    22、 获取网站技术的插件

    * wappalyzer
    获取到当前网站的使用的技术

    23、vue-router

    * 前端路由 核心就是锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据

    *ui-router:锚点值改变,如何获取模板? ajax

    *vue中,模板数据不是通过ajax请求来,而是调用函数获取到模板内容

    *核心:锚点值改变
    *以后看到vue开头,就知道必须Vue.use
    * vue的核心插件:
    -vue-router 路由
    -vuex 管理全局共享数据
    *使用方式
    -1:下载 `npm i vue-router -S`
    -2:在main.js 中引入`import VueRouter from 'vue-router'`
    -3:安装插件`Vue.use(VueRouter)`
    -4:创建路由对象并配置路由规则
    + `let router = neew VueRouter({routes:[{path:'/home',component:Home}]})`
    -5:将其路由对象传递给Vue 的实例,options中
    + options中加入`router:router`
    -6:在app.vue中留坑
    <!-- 留坑,非常重要 -->
    <router-view></router-view>

    24、 Vue 学习方式

    vue:这个对象怎么来的?
    框架的使用,关注vue代码怎么写,不会照抄
    框架,先掌握运用

    组件的组成部分:

    结构、样式、动态效果

    基于webpack 编译——>核心,最终理解打包的好处

    25、 命名方式使用router-link

    //创建路由对象并配置路由规则
    let router = new VueRouter({
    routes:[
    //一个个对象
    {name:'music',path:'/myMusic',component:Music},
    {path:'/movie',component:Movie}
    ]
    })
    *router-link实际是根据name 找到对应的路径;
    <!-- 1、去哪里 -->
    <router-link :to="{name:'music'}">进入音乐1</router-link>
    <router-link :to="{name:'music'}">进入音乐2</router-link>
    <router-link :to="{name:'music'}">进入音乐3</router-link>
    <!-- 也可以跟路径使用 ,但是不建议使用-->
    <router-link to="/movie">进入电影</router-link>
    Vue.use(VueRouter);//挂载属性

    二、基础学习

    1、 vue中响应的数据绑定和视图组件

    可以从github上找vue的学习资源
    1:渐进式框架Vue

    Vue是什么

    构建用户界面的渐进式框架
    只关注视图层(view)

    2:vue中两个核心点

    vue中两个核心点
    1:响应的数据绑定

    1)当数据发生改变->自动更新视图
    2)利用Object.definedProperty (不兼容IE8)中的setter/getter代理数据,监控对数据的操作

    2: 组合的视图组件

    1) ui页面映射为组件树
    2) 划分组件可维护、可重用、可测试


    3:虚拟DOM

    运行js的速度是很快的,大量操作DOM就会很慢时常在更新数据后会重新渲染页面造成资源浪费。

    4:MVVM模式

    M:model 数据模型
    V:view 视图模型
    VM:view-Model 视图模型

    经典例子:(这里是引入vue.js的代码写法)
    <div id="demo">
    <input type="text" v-model="message"/>
    <p>{{message}}</p>
    </div>
    let data = {message:'hello,world'};
    var vm = new Vue({
    el:'#demo',
    data:data
    });

    5:Vue实例

    *vue实例
    每一个应用都是通过Vue这个构造函数创建根实例启动new Vue(选项对象)
    * 需要传入选项对象,对象包含挂载元素,数据,模板,方法等。
    el: 挂载元素选择器 String|HtmlElement
    data: 代理数据 Object|Function
    methods:定义方法 Object

    *vue代理data数据

    每个Vue实例都会代理其data对象里所有的属性,这些被代理的属性是响应的。新添加的属性不具备响应功能,改变后不会更新视图。

    * vue 实例自身属性和方法
    暴露自身属性和方法:以$ 开头,例如 $el $data....

    6:声明式渲染

    *声明式:只需要声明在哪里做什么,而无需关心如何实现

    *命令式:需要以具体代码表达在哪里做什么,如何实现
    var arr = [1,2,3,4,5];
    //求数组中每一项的倍数,放在另一个数组中
    for(var i=0;i<arr.length;i++){
    newArr.push(arr*2);
    }
    var newArr = arr.map(function(){});

    *vue声明式渲染:
    arr.map(function(item){
    return item*2
    });

    7:指令

    什么是指令
    是一种特殊的自定义行间属性
    指令的职责就是当其表达式的值改变时相应地某些行为应用到DOM上
    在Vue中,指令以v-开头
    8:模板
    9:vue中的双向数据绑定

    1)Vue中的内置指令:
    v-bind 动态的绑定数据,简写为:
    v-on绑定事件监听器,简写为@
    v-text 更新数据,会覆盖已有结构
    v-html 可以解析数据中的html结构
    v-show 根据值的真假,切换元素的display属性
    v-if 根据值的真假,切换元素会被销毁、重建
    v-else-if 多条件判断,为真则渲染
    v-else 条件都不符合渲染
    v-for 基于元数据多次渲染元素或模板块
    v-model 在表单控件元素上创建双向数据绑定
    v-pre 跳过元素和子元素的编译过程
    v-once 只渲染一次,随后数据更新不重新渲染
    v-cloak 隐藏未编译的Mustache语法,css中设置[vcloak]{display:none}

    2)html模板

    基于DOM的模板,模板都是可解析的有效的HTML

    插值:
    文本: 使用"Mustache"语法,(双大括号){{value}}
    作用:替换实例上的属性值,当值改变时,插值内容处会自动更新

    原生的html:双大括号输出的是文本,不会解析html(如果想要解析成html而不是文本,需要在标签中添加 v-html ,v-html="html" 记住 span中不能包含div )

    属性:使用v-bind进行绑定,可以响应变化

    使用javascript表达式:写简单的表达式

    {{1+2}} {{ture?"yes":"no"}

    3)template 字符串模板

    template选项对象的属性
    模板将会替换挂载的元素。挂载元素的内容都将被忽略
    根节点只能有一个(template中只能写一个根节点不能有并列的)
    var vm = new Vue({
    el:'#demo',
    data:{abc:123},
    template:`<div>{{abc}}<span>hello</span></div>`
    })
    将html结构写在一对script标签中,设置type="x-template"
    即将template的html写在script中,如:
    <script type="x-template" id="temp">
    <div>{{abc}}
    <span>hello</span>
    </div>
    </script>
    var vm = new Vue({
    el:'#demo',
    data:{abc:123},
    template:"#temp"
    })

    4)模板 -render函数

    render 选项对象的属性
    createElement(标签名,数据对象(可省略),子元素)
    绑定的class,值是一个对象,对象的key是class名称,value是一个表达式,能判断出是true还是false;
    <div id="demo">
    <span :class='{red:addClass}'></span>
    </div>
    <style>
    .red{
    background-color:red;
    }
    .bg{
    background:red
    }
    </style>
    var obj = {
    addClass:true
    }
    var vm = new Vue({
    el:'#demo',
    data:obj,
    render(creareElement){
    return creareElement(
    "ul", //标签名
    {
    class:{
    bg:true
    },
    style:{
    fontSize:"50px"
    },
    attrs:{
    abc:"hello"
    }
    },
    [
    creareElement("li",1),
    creareElement("li",2),
    creareElement("li",3),
    ]
    )
    }
    })

    render 函数第二个参数,数据对象属性:
    class:{} //绑定class,和‘v-bind:class’一样的API
    style:{} //绑定样式,和 'v-bind:style' 一样的 API
    attrs:{} //添加行间属性
    domProps:{} //DOM 元素属性
    on:{} //绑定事件

    nativeOn:{} //监听原生事件
    directives:{} //自定义指令
    scopedSlots:{} //slot作用域
    slot:{}, // 定义slot名称
    key:"key" //给元素添加唯一标示
    ref:"ref" //引用信息

    10:翻译API地址:https://tech.yandex.com/translate/

    11:命令行工具(cli),用于快速搭建大型单页应用

    npm install --global vue-cli
    vue init webpack my-project
    cd my-project
    npm install 加载需要的模块
    npm run dev

    12: 在线翻译项目总结

    1、搭建项目开发环境
    2、创建根组件和子组件
    3、在根组件中引入translateForm组件,完善此子组件,看组件都包括什么,然后写代码。将这些代码包裹在form中,为form绑定事件,为了提交form中的东西
    4、需要拿到输入的内容,使用组件中data方法,定义一个属性,使用此属性通过v-model的方法,将值绑定到input上。
    5、将上述拿到的值传递给根组件,通过 this.$emit("方法名(自己随便定义,如formSubmit)")(其实是注册一个事件)
    然后在根组件中的translateForm 标签中绑定这个事件,如:<translateForm v-on:formSubmit="事件名"></translateForm>
    如事件名为 translateText,此时点击翻译按钮,就能调用tanslateText这个函数了。this.$emit("方法名(自己随便定义,如formSubmit)",需要传递的参数(如this.textToTranslate))
    参数传递过去之后需要有地方接收,即在tanslateText这个函数中添加形参。
    6、上述拿到想要翻译的内容之后,需要进行翻译,这时需要借助翻译的api,需要使用http请求调用接口,使用http就需要安装vue-resource(因vuejs的作者宣布不再继续维护vue-resource,并推荐大家使用axios)。
    安装好之后,需要在main.js 中引入该模块,import VueResource form './App'
    引入进来之后,要使用Vue.use(VueResource)
    在 tanslateText 中调用接口:
    this.$http.get('https://translate.yandex.net/api/v1.5/tr.json/translate?key=trnsl.1.1.20171103T033211Z.f02fec6e631bce1f.d4c2b02b1d3981280c37eba265247f888c3e5215')需要传的参数是文本和language
    使用.then()接收http的返回值
    .then((reponse)=>{
    reponse下的body下的text[0]就是我们翻译出来的值
    })
    将翻译出来的值放到页面中:
    在App.vue 的data下返回一个 translatedText属性,然后将response中拿到的值赋值给此属性
    将此属性传递给translateOutput,首先在App.vue中引入translateOutput组件,在app.vue中输入
    <translateOutput></translateOutput> ,通过v-text绑定translatedText 这个属性,如下:
    <translateOutput v-text="translatedText"></translateOutput>,传过来之后,在 translateOutput中定义一个属性 props:["translatedText"],在translateOutput中调用此属性<div id="translateOutput">
    {{translatedText}}
    </div>
    select 中也通过v-model 来传递language的值,作为参数传给根组件,
    created 方法不需要调用,默认会执行。

    13: www.worktile.com 员工协作的平台
    Vue
    Vuex 一种状态管理模式
    Vue-router
    webpack 模块打包工具
    NodeJS 运行在服务器端的JavaScript
    Express 一个简洁而灵活的node.js Web 应用框架,
    提供了一系列强大特性帮助你创建各种Web 应用和丰富的HTTP工具

    MongoDB 是一个基于分布式文件存储的数据库,旨在为WEB 应用提供
    可扩展的高性能数据存储解决方案。
    Mongoose 是在node.js 环境下对mongodb 进行便捷操作的对象模型工具

    小插曲: 查找端口号1099的PID 命令:netstat -ano|findstr "1099"

    14:Vue.js API

    1、全局配置
    Vue.config 是一个对象,包含 Vue 的全局配置。可以在启动应用之前修改它的属性。

    silent
    optionMergeStrategies
    devtools
    errorHandler
    warnHandler
    ignoredElements
    keyCodes
    performance
    productionTip

    未完待续.......

  • 相关阅读:
    关于云计算:IaaS的四个误解和四个猜想 浪峰小园子
    国外10个优秀的免费轻量级CMS系统 浪峰小园子
    Win8下80端口被System占用,造成Apache不能启动的解决办法 浪峰小园子
    [转载]基于内存数据库的分布式数据库架构何坤 浪峰小园子
    php短域名转换为实际域名函数 浪峰小园子
    [转载]苹果公司与分工原理 浪峰小园子
    PHPer的等级划分
    简单的无限分类树
    转换字符串编码
    php开启虚拟域名功能
  • 原文地址:https://www.cnblogs.com/WEI-web/p/7799110.html
Copyright © 2011-2022 走看看