1、分析脚手架

├── node_modules
├── public
│   ├── favicon.ico: 页签图标
│   └── index.html: 主页面
├── src
│   ├── assets: 存放静态资源
│   │   └── logo.png
│   │── component: 存放组件
│   │   └── HelloWorld.vue
│   │── App.vue: 汇总所有组件
│   │── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
├── package-lock.json:包版本控制文件

2、render函数

//main.js
import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = falsenew Vue({el:"#app",render(createElement){return createElement('h1',"你好啊")}
})


render是函数,能创建元素,再精简点

  render: createElement=>createElement('h1',"你好啊")
new Vue({el:"#app",render:h=>h(App)})

关于不同版本的Vue:
1.vue.js与vue.runtime.xxx.js的区别:
(1).vue.js是完整版的Vue,包含:核心功能+模板解析器
(2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。
2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容。

3、默认配置

Vue 脚手架隐藏了所有 webpack 相关的配置,若想查看具体的 webpakc 配置,
终端输入vue inspect > output.js
使用vue.config.js可以对脚手架进行个性化定制,详情见官网

module.exports = {pages: {index: {//入口entry: 'src/main.js',},},lintOnSave:false//关闭语法检查}

4、ref属性

1.获取原生dom元素原生里用id来操作,vue里面用ref,被用来给元素或子组件注册引用信息(id的替代者)
2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3. 使用方式:

  1. 打标识:<h1 ref="xxx">.....</h1><School ref="xxx"></School>
  2. 获取:this.$refs.xxx
<template><div><h1 v-text="msg" ref="title"></h1><button ref="btn" @click="showDOM">点我</button><School></School><Student></Student></div>
</template><script>//引入组件import School from './components/School'import Student from './components/Student'export default {name:'App',data(){return{msg:"2021/9/14"}},components:{School,Student},methods:{showDOM:function(){console.log(this.$refs.title);console.log(this.$refs.btn);}}}
</script>

5、props配置

  1. 功能:让组件接收外部传过来的数据
  2. 传递数据:<Demo name="xxx"/>
  3. 接收数据:
    1. 第一种方式(简单声明接收):props:['name','age','sex']
    2. 第二种方式(限制数据类型):
props:{name:String,age:Number,sex:String}
  1. 第三种方式(限制类型、限制必要性、指定默认值):
 props:{name:{type:String, //类型required:true, //必要性default:'老王' //默认值}}

示例

//app.vue
<template><div><Student name="李四" sex="女" :age="18+1"></Student></div>
</template><script>//引入组件import Student from './components/Student'export default {name:'App',components:{Student}}
</script>
//student.vue
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{age}}</h2></div>
</template><script>export default {name:'Student',props:['name','age','sex']}
</script>

动态绑定,计算双引号里面的值

 <Student name="李四" sex="女" :age="18+1"></Student>

<Student name="李四" sex="女" age="18+1"></Student>

如果组件中也定义了相同名称的数据

<script>export default {name:'Student',data(){return{age:12}},props:{name:String,age:Number,sex:String}}
</script>


备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告。

<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{age}}</h2><button @click="showAge">点我</button></div>
</template><script>export default {name:'Student',methods:{showAge:function(){this.age++}},//props:['name','age','sex'],//简单接收props:{name:String,age:Number,sex:String}}
</script>


若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{thisAge}}</h2><button @click="showAge">点我</button></div>
</template><script>export default {name:'Student',data(){return{thisAge:this.age}},methods:{showAge:function(){this.thisAge++}},//props:['name','age','sex'],//简单接收props:{name:String,age:Number,sex:String}}
</script>
Cate.vue
<template><div class="cate"><h3>title</h3><ul><li v-for="item in listData">{{item}}</li></ul></div>
</template><script>
export default {name:"Cate",
props:["listData","title"]
}
</script><style>
.cate{background-color:skyblue;width: 200px;height: 300px;
}
h3{text-align: center;
}</style>
//App.vue
<template><div class="container"><Cate :listData="foods" title="foods"/><Cate :listData="games" title="games"/><Cate :listData="films" title="films"/></div>
</template><script>
import Cate from './components/Cate'
export default {name:'App',
components:{Cate
},
data(){return{foods:["火锅","烧烤","炸鸡","泡面"],games:["超级玛丽","奥比岛","洛克王国","摩尔庄园"],films:["教父","峰暴","一天","巧克力工厂"],}
}
}
</script><style>
.container{display: flex;justify-content: space-around;
}
</style>

6、mixin混入

多个组件共享一个配置

  1. 功能:可以把多个组件共用的配置提取成一个混入对象
  2. 使用方式:
    第一步定义混合:
   {data(){....},methods:{....}....}
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2><button @click="showName">点我</button></div>
</template><script>import {mixin}from'../mixin.js'export default {name:'Student',data(){return{name:"张三",sex:"男"}},mixins:[mixin]}
</script>
//minin.js
export const mixin={methods:{showName:function(){console.log(this.name)}
}}

第二步使用混入:
全局混入:Vue.mixin(xxx)在main.js中写入
局部混入:mixins:['xxx']在组件中写

7、插件

  1. 功能:用于增强Vue
  2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据
  3. 定义插件:
//plugins.js对象.install = function (Vue, options) {// 1. 添加全局过滤器Vue.filter(....)// 2. 添加全局指令Vue.directive(....)// 3. 配置全局混入(合)Vue.mixin(....)// 4. 添加实例方法Vue.prototype.$myMethod = function () {...}Vue.prototype.$myProperty = xxxx}
  1. 使用插件:Vue.use()
//main.js//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import plugins from './plugins'
//关闭Vue的生产提示
Vue.config.productionTip = false//应用(使用)插件
Vue.use(plugins,1,2,3)
//创建vm
new Vue({el:'#app',render: h => h(App)
})

8、scoped样式

  1. 作用:让样式在局部生效,防止冲突。
  2. 写法:<style scoped>
  3. 写在App.vue不太适用
    安装less-loader
npm i less-loader@7.2.3

查看插件版本

npm view less-loader versions
<style lang="less" scoped>.demo{background-color: pink;.atguigu{font-size: 40px;}}
</style>

9、浏览器缓存

  1. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
  2. 浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。
  3. 相关API:
    xxxxxStorage.setItem('key', 'value');该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
    JSON.stringify将 JavaScript 值转换为 JSON 字符串
    JSON.parse将数据转换为 JavaScript 对象
    xxxxxStorage.getItem('person');
    该方法接受一个键名作为参数,返回键名对应的值。
    xxxxxStorage.removeItem('key');
    该方法接受一个键名作为参数,并把该键名从存储中删除。
    xxxxxStorage.clear()
    该方法会清空存储中的所有数据。
  4. 备注:
    1. SessionStorage存储的内容会随着浏览器窗口关闭而消失。
    2. LocalStorage存储的内容,需要手动清除才会消失。
    3. xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么getItem的返回值是null。
    4. JSON.parse(null)的结果依然是null。

10、组件自定义事件

通过父组件给子组件传递函数类型的props实现:子给父传递数据

//School.vue
<template><div><h2>学校:{{name}}</h2><h2>地址:{{address}}</h2><button @click="sendSchoolName">点我</button></div>
</template><script>export default {name:'School',data(){return{name:"一中",address:"广州"}},props:['getSchoolName'],methods: {sendSchoolName(){//传递过来了以后要调用this.getSchoolName(this.name)}},}
</script>
//App.vue
<template><div><Student></Student><hr>//通过父组件给子组件传递函数类型的props实现:子给父传递数据<School :getSchoolName="getSchoolName"></School></div>
</template><script>//引入组件
import Student from './components/Student.vue'
import School from './components/School.vue'export default {name:'App',components:{Student,School},methods:{getSchoolName:function(name){console.log("App收到了name",name);},}}
</script>

通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on)

//App.vue
<template><div><Student @dianji="getStudentName"/>//父组件给子组件绑定一个自定义事件实现</div>
</template><script>//引入组件
import Student from './components/Student.vue'export default {name:'App',components:{Student,},methods:{getStudentName(name,...params){console.log('App收到了学生名:',name,params)this.studentName = name},}}
</script>
//Student.vue
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2><button @click="sendStudentlName">点我</button></div>
</template><script>import {mixin}from'../mixin.js'export default {name:'Student',data(){return{name:"张三",sex:"男"}},methods:{sendStudentlName(){//需要绑定点击触发//触发Student组件实例身上的dianji事件//子给父传递数据this.$emit('dianji',this.name,666,888,900)},}}
</script>

通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref

//App.vue
<template><div><Student ref="student"/></div>
</template><script>//引入组件
import Student from './components/Student.vue'
import School from './components/School.vue'export default {name:'App',components:{Student,School},methods:{getStudentName(name,...params){console.log('App收到了学生名:',name,params)this.studentName = name},},mounted() {//给student标签绑定一个点击事件,然后这个事件会调用方法this.$refs.student.$on('dianji',this.getStudentName) //绑定自定义事件// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事(一次性)},}
</script>
//Student.vue
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2><button @click="sendStudentlName">点我</button></div>
</template><script>import {mixin}from'../mixin.js'export default {name:'Student',data(){return{name:"张三",sex:"男"}},methods:{sendStudentlName(){//触发Student组件实例身上的dianji事件this.$emit('dianji',this.name,666,888,900)},}}
</script>


一个是通过vue的@绑定自定义事件,一个是通过ref属性获取到dom元素然后绑定自定义事件

  1. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。
  2. 触发自定义事件:this.$emit('dianji',数据)
  3. 解绑自定义事件this.$off('dianji')
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2><button @click="sendStudentlName">点我输出</button><button @click="unbind">点我解绑</button></div>
</template>
<script>export default {name:'Student',data(){return{name:"张三",sex:"男"}},methods:{sendStudentlName(){//触发Student组件实例身上的dianji事件this.$emit('dianji',this.name,666,888,900)},unbind(){this.$off("dianji")//解绑一个事件this.$off(["dianji","demo"])//解绑多个事件this.$off()//解绑所有事件}},}
</script>

如果调用this.destory,那么所有自定义属性都会被解绑,因为绑定的实例对象已经被销毁了
4. 组件上也可以绑定原生DOM事件,需要使用native修饰符,不然会默认认为绑定的是自定义事件。

<Student ref="student" @click.native="方法名"></Student>
  1. 注意:通过this.$refs.xxx.$on('dianji',回调函数)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

11、全局事件总线

  1. 一种组件间通信的方式,适用于任意组件间通信。
  2. 安装全局事件总线:
//App.vuenew Vue({......beforeCreate() {//this指向这个vue实例对象Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm},......})
  1. 使用事件总线:

    1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
  methods(){demo(data){......}}......mounted() {this.$bus.$on('xxxx',this.demo)}
  1. 提供数据:this.$bus.$emit('xxxx',数据)
  2. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件

实现Student、School组件间的相互通信,Student组件传递信息给School组件,School组件绑定自定义方法,然后Student组件emit触发,并且传递参数进行通信,

//main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
//创建vm
new Vue({el:'#app',render: h => h(App),beforeCreate() {Vue.prototype.$bus = this //安装全局事件总线},
})
//Student.vue
<template><div class="student"><h2>学生姓名:{{name}}</h2><h2>学生性别:{{sex}}</h2><button @click="sendStudentName">把学生名给School组件</button></div>
</template><script>export default {name:'Student',data() {return {name:'张三',sex:'男',}},mounted() {// console.log('Student',this.x)},methods: {sendStudentName(){this.$bus.$emit('hello',this.name)}},}
</script>
//School.vue
<template><div class="school"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2></div>
</template>
<script>export default {name:'School',data() {return {name:'二中',address:'北京',}},mounted() {// console.log('School',this)this.$bus.$on('hello',(data)=>{console.log('我是School组件,收到了数据',data)})},beforeDestroy() {this.$bus.$off('hello')},}
</script>

12、消息的订阅和发布

  1. 一种组件间通信的方式,适用于任意组件间通信。
  2. 使用步骤:
    1. 安装pubsubnpm i pubsub-js
    2. 引入: import pubsub from 'pubsub-js'
    3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
    4. 提供数据:pubsub.publish('xxx',数据)
    5. 最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。

School组件订阅然后Student组件发布信息实现组件间的通信
语法:
(1) import PubSub from ‘pubsub-js’ // 引入
(2) PubSub.subscribe(‘msgName’, functon(msgName, data){ })
(3) PubSub.publish(‘msgName’, data): 发布消息, 触发订阅的回调函数调用
(4) PubSub.unsubscribe(token): 取消消息的订阅

//School.vue
<template><div><h2>学校:{{name}}</h2><h2>地址:{{address}}</h2></div>
</template><script>
import pubsub from 'pubsub-js'export default {name:'School',data(){return{name:"一中",address:"广州"}},mounted(){this.pubId =pubsub.subscribe('hello',(a,b)=>{console.log("11111111111",a,b)})},beforeDestroy() {pubsub.unsubscribe(this.pubId)//取消订阅},}
</script>
//Student.vue
<template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{sex}}</h2>
<button @click="sendStudentName">把数据传递给School组件</button></div>
</template><script>
import pubsub from 'pubsub-js'export default {name:'Student',data(){return{name:"张三",sex:"男"}},mounted(){},methods:{sendStudentName(){pubsub.publish('hello',this.name)}}}
</script>

13、this.$nextTick

  1. 语法:this.$nextTick(回调函数)
  2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
  3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
<template><button ref="tar" type="button" name="button" @click="testClick">{{content}}</button>
</template><script>export default {data () {return {content: '初始值'}}methods: {testClick(){this.content = '改变了的值'// 这时候直接打印的话,由于dom元素还没更新// 因此打印出来的还是未改变之前的值console.log(this.$refs.tar.innerText) // 初始值}}}
</script>

this.$nextTick这个方法作用是当数据被修改后使用这个方法会回调获取更新后的dom再渲染出来

methods:{testClick() {this.content = '改变了的值'let that = thisthis.$nextTick(() => {// dom元素更新后执行,因此这里能正确打印更改之后的值console.log(that.$refs.tar.innerText) // 改变了的值})}
}

14、插槽

作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件 ===> 子组件

14.1、默认插槽

如果组件标签里没有插入内容的时候,不会显示
如果有插入内容,会显示
父组件中:

//App.vue<Category><div>html结构1</div></Category>

当使用的组件标签中插入内容时,插入的内容会被放到组件的slot标签中
子组件中:

//Category.vue
<template><div><!-- 定义插槽 --><slot>我是默认内容</slot></div>
</template>

像下面组件标签中加入了图片标签

//App.vue
<template><div class="container"><Category :listData="foods" title="foods"><img src="https://z3.ax1x.com/2021/09/25/4rtPMV.png" alt=""></Category></div>
</template>


如果组件标签内没有没有放标签

//App.vue
<template><div class="container"><Category :listData="foods" title="foods"></Category></div>
</template>

组件标签中没有插入其他标签

14.2、具名插槽

具名插槽则是当子组件需要显示不同的效果时使用具名插槽,通过name属性给插槽命名。

父组件中:

写法一:

//App.vue<Category><template slot="center"><div>html结构1</div></template></Category>

写法二:

//App.vue<Category><template v-slot:footer><div>html结构2</div></template></Category>

子组件中:

//Category.vue<template><div><!-- 定义插槽 --><slot name="center">插槽默认内容...</slot><slot name="footer">插槽默认内容...</slot></div></template>

具体代码

//Cate.vue
<template><div class="cate"><h3>title</h3><slot name="center">我是默认值1111</slot><slot name="footer">我是默认值2222</slot></div>
</template><script>
export default {name:"Cate",
props:["listData","title"]
}
</script><style>
.cate{background-color:skyblue;width: 200px;height: 300px;
}
h3{text-align: center;
}</style>
//App.vue
<template><div class="container"><Cate title="foods"><img slot="center" src="https://z3.ax1x.com/2021/09/25/4rtPMV.png" alt=""><template v-slot:footer><h4>更多图片</h4></template></Cate></div>
</template><script>
import Cate from './components/Cate'
export default {name:'App',
components:{Cate
},
data(){return{foods:["火锅","烧烤","炸鸡","泡面"],games:["超级玛丽","奥比岛","洛克王国","摩尔庄园"],films:["教父","峰暴","一天","巧克力工厂"],}
}
}
</script><style>
.container{display: flex;justify-content: space-around;
}
img{width: 100%;
}
</style>>


14.3、作用域插槽

理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
需要组件的使用者收到了数据,怎么使用取决于组件的使用者
(games数据在Cate组件中,但使用数据所遍历出来的结构由App组件决定)
作用域插槽语法,必须要使用template

 <template scope="scopeData">{{scopeData}}</template>
//App.vue
<template><div class="container"><Cate><template scope="scopeData">{{scopeData}}</template></Cate></div>
</template><script>
import Cate from './components/Cate'
export default {name:'App',
components:{Cate
}
}
</script>
//Cate.vue
<template><div class="cate"><h3>{{title}}</h3><slot :games="games">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
</div>
</template><script>
export default {name:"Cate",
props:["title"],
data(){return{games:["超级玛丽","奥比岛","洛克王国","摩尔庄园"],}
}
}
</script>
 <template scope="scopeData">{{scopeData}}</template>

这个收到是一个对象,就是下面图所示,我们需要的是.games

 <template scope="scopeData">{{scopeData.games}}</template>

Vue进阶脚手架开发相关推荐

  1. Vue进阶(五十三):vue-cli 脚手架 webpack.prod.conf.js 配置文件详解

    文章目录 一.前言 二.optimize-css-assets-webpack-plugin 插件 三.拓展阅读 一.前言 webpack.prod.conf.js 配置文件是webpack生产环境核 ...

  2. Vue教程03-Vue脚手架开发环境

    Vue脚手架开发环境 1.Vue开发环境的安装 1.1安装Node JS 1.2全局安装Vue脚手架 1.3安装HBuilderX 1.4强烈推荐安装以下工具软件 2.HBuilderX创建Vue项目 ...

  3. ehcache springboot_阿里内部进阶学习SpringBoot+Vue全栈开发实战文档

    前言 Spring 作为一个轻量级的容器,在JavaEE开发中得到了广泛的应用,但是Spring 的配置烦琐臃肿,在和各种第三方框架进行整合时代码量都非常大,并且整合的代码大多是重复的,为了使开发者能 ...

  4. Vue项目构建开发入门

    Vue项目构建开发入门 开篇:Vue CLI 3 项目构建基础 大家好,当你点进这个标题,开始阅读本章的时候,说明你对 Vue.js 是充满好奇心和求知欲的.我之前写过一篇文章,这样评价 Vue.js ...

  5. Vue进阶——Vue CLI

    Vue进阶--Vue CLI 前言 一.什么是Vue CLI? 二.怎么安装Vue CLI? 1.Node 版本要求 2.已安装旧版本 3.安装完成 三.Vue CLI 基础运用 1.Vue ui项目 ...

  6. Vue进阶(二):Vue 项目文件结构介绍

    文章目录 一.文件介绍 二.Vue 加载 main.js 过程分析 三.注 四.拓展阅读 一.文件介绍 main.js是项目主入口文件,主要作用是初始化vue实例,并引入所需插件: App.vue是项 ...

  7. vue.cli脚手架初次使用图文教程

    vue-cli作用 vue-cli作为vue的脚手架,可以帮助我们在实际开发中自动生成vue.js的模板工程. vue-cli使用 !!前提:需要vue和webpack 安装全局vue-cli npm ...

  8. VUE学习和开发中的注意点总结(一),便于回顾(不断完善补充。)

    1.export 和export default 的区别? 在JavaScript ES6中,export与export default均可用于导出常量.函数.文件.模块等,你可以在其它文件或模块中通 ...

  9. Vue 基础的开发环境

    本期节目将手把手教你去 NPM 市场买最新鲜的食材,只为搭配 小鲜肉 Vue 下厨. 既然它是当红小鲜肉,我想有必要写一篇文章来帮助大家配置好 Vue 的生产环境,我给它的总体评价是"简单却 ...

最新文章

  1. 生物信息行业应该具备哪些基础素养?重点应该放在计算机方面还是生物方面或者说其他?
  2. call_user_func
  3. 山西五台警方通报“男子强拽女学生”:嫌疑人被刑拘
  4. js获取浏览器活跃页面,切换tab页状态
  5. Android学习笔记(一)
  6. Flask使用Flask-SQLAlchemy操作MySQL数据库
  7. [转载] java8 lambda表达式 List转为Map
  8. Maven的下载与安装
  9. 微服务(接口)设计原则
  10. 还有在用迅雷7的朋友吗?
  11. 移动通信(Mobile Communication)
  12. 用Python实现双色球随机选号
  13. Word批量打印软件/工具
  14. 音频amr格式怎么转成mp3-几个步骤轻松搞定
  15. 推荐10款最好的免费项目管理工具
  16. usb计算机连接 不再弹出,电脑usb无法安全弹出问题解决办法
  17. 【渝粤教育】电大中专电商运营实操 (4)作业 题库
  18. python图像切割成多边形_python opencv在图像中裁剪任意形状多边形,裁剪镂空多边形, 裁剪多个多边形...
  19. 2022中国眼博会,中国北京国际儿童青少年眼睛健康产业展览会
  20. 汽车租赁APP应用开发

热门文章

  1. SoapUI解析webservice 中的xml文件,进行接口调试
  2. 医药企业数字化转型的技术架构和演变策略
  3. Ubuntu安装QQ、微信,百度网盘。deepinQQ、deepin微信(针对版本不兼容问题)、deepin百度网盘
  4. 如何实现秒杀(逻辑过程)
  5. 支付宝小程序 | 上传图片组件(添加默认样式以及自定义上传样式)
  6. 我男朋友是个程序员……# 1
  7. android 主线程和子线程交互方式
  8. Photoshop如何使用文字之实例演示?
  9. WPS删除图片被裁剪掉的部分
  10. Android@id和@+id区别