大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

看完你就基本可以上手搞开发了,本文适合Vue初学者,或者Vue2迁移者,当然还是建议Vue3官网完全过一遍。不适合精通原理,源码的大佬们。

先推荐两个vscode插件

Volar

首先推荐Volar,使用vscode开发Vue项目的小伙伴肯定都认识Vetur这个神级插件,有了它可以让我们得开发如鱼得水。那么Volar可以理解为Vue3版本的Vetur,代码高亮,语法提示,基本上Vetur有的它都有。

特色功能

当然作为新的插件出山,肯定有它独有的功能。

多个根节点编辑器不会报错

Vue3是允许我们有多个根节点的,但是我们如果使用Vetur就会报错,不会影响运行,但是看起来就很烦。所以当我们转向Volar那么就不会出现这个问题了。

image.png

编辑器分隔

即便Vue的组件化开发,可以将单文件的代码长度大幅缩短,但还是动辄几百行甚是上千行。那么我们切换templatescriptstyle的时候就要频繁上下翻,虽然有的插件可以直接定位到css,但是你回不去啊!所以这个功能简直是太人性化了。

安装完Volar以后,打开一个.vue文件,看vscode的右上角,有这么一个图标,点一下。

image.png

它就会自动给你分隔成三个页面,分别对应templatescriptstyle,这样就太舒服了有没有。

image.png

Vue 3 Snippets

推荐的第二个插件叫做Vue 3 Snippets,同样的,他也有自己的Vue2版本。它是干什么的呢,可以看一下下面这张图,我只输入了“v3”,它有很多提示,我们就先选择v3computed,选中回车即可。

image.png

然后它就给自动给我们写了如下代码

image.png

是不是超级省事,摸鱼的时间又增加了!还有更多有趣的使用方式,小伙伴们自行探索吧。

创建Vue3项目

那么正式开始学习我们的Vue3,先从创建项目开始。

使用 vue-cli 创建

输入下面的命令然后选择配置项进行安装即可,这里注意vue-cli的版本一定要在4.5.0以上

// 安装或者升级
npm install -g @vue/cli
//查看版本 保证 vue cli 版本在 4.5.0 以上
vue --version
// 创建项目
vue create my-project
//然后根据提示一步一步傻瓜式操作就行了
...
复制代码

使用 Vite 创建

都说Vue3.0Vite2更配,各种优化,各种快,但都不属于本文的内容,本文的目的我们只需要知道它特别好用,怎么用就行了。我这里是多选择了TS,每行都有注释,一目了然。

// 初始化viete项目
npm init vite-app <project-name>
// 进入项目文件夹
cd <project-name>
// 安装依赖
npm install
//启动项目
npm run dev
复制代码

创建完以后我们先来看看入口文件main.ts

// 引入createApp函数,创建对应的应用,产生应用的实例对象
import { createApp } from 'vue';
// 引入app组件(所有组件的父级组件)
import App from './App.vue';
// 创建app应用返回对应的实例对象,调用mount方法进行挂载  挂载到#app节点上去
createApp(App).mount('#app');
复制代码

然后看看根组件app.vue

//Vue2组件中的html模板中必须要有一对根标签,Vue3组件的html模板中可以没有根标签
<template><img alt="Vue logo" src="./assets/logo.png"><!-- 使用子级组件 --><HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
</template><script lang="ts">
// 这里可以书写TS代码// defineComponent函数,目的是定义一个组件 内部可以传入一个配置对象
import { defineComponent } from 'vue';
//引入子级组件
import HelloWorld from './components/HelloWorld.vue';// 暴露出去一个定义好的组件
export default defineComponent({// 当前组件的名字name: 'App',// 注册组件components: {// 注册一个子级组件HelloWorld,},
});
</script>
复制代码

Composition API

接下来到了重头戏,Vue3的招牌特性,Composition API

关于Composition API这里有大佬做的动画演示,极力推荐。

那个忙了一夜的Vue3动画很好,就是太短了

Composition API可以更方便的抽取共通逻辑,但是不要过于在意逻辑代码复用,以功能提取代码也是一种思路。

顺便提一句,Vue3兼容大部分Vue2语法,所以在Vue3中书写Vue2语法是没有问题的(废除的除外),但是既然我们已经升级Vue3了,不建议混合使用,除非一些大型特殊项目需要兼容两个版本。

setup

setup是组合Composition API中的入口函数,也是第一个要使用的函数。

setup只在初始化时执行一次,所有的Composition API函数都在此使用。

setup() {console.log('我执行了') //我执行了
},
复制代码

可以通过console.log看到setup是在beforeCreate生命周期之前执行的(只执行一次)

beforeCreate() {console.log('beforeCreate执行了');},setup() {console.log('setup执行了');return {};},//setup执行了//beforeCreate执行了
复制代码

由此可以推断出setup执行的时候,组件对象还没有创建,组件实例对象this还不可用,此时thisundefined, 不能通过this来访问data/computed/methods/props

返回对象中的属性会与data函数返回对象的属性合并成为组件对象的属性,返回对象中的方法会与methods中的方法合并成功组件对象的方法,如果有重名, setup优先。因为在setupthis不可用,methods中可以访问setup提供的属性和方法, 但在setup方法中不能访问datamethods里的内容,所以还是不建议混合使用。

setup函数如果返回对象, 对象中的 属性 或 方法 , 模板 中可以直接使用

//templete
<div>{{number}}</div>//JS
setup() {const number = 18;return {number,};
},
复制代码

注意:setup不能是一个async函数: 因为返回值不再是return的对象, 而是promise, 模板中就不可以使用return中返回对象的数据了。

setup的参数(props,context)`

props: 是一个对象,里面有父级组件向子级组件传递的数据,并且是在子级组件中使用props接收到的所有的属性

context:上下文对象,可以通过es6语法解构 setup(props, {attrs, slots, emit})

  • attrs: 获取当前组件标签上所有没有通过props接收的属性的对象, 相当于 this.$attrs

  • slots: 包含所有传入的插槽内容的对象, 相当于 this.$slots

  • emit: 用来分发自定义事件的函数, 相当于 this.$emit

演示attrsprops

//父组件
<template><child :msg="msg" msg2='哈哈哈' />
</template>
<script lang='ts'>
import { defineComponent, ref } from 'vue';
// 引入子组件
import Child from './components/Child.vue';
export default defineComponent({name: 'App',components: {Child,},setup() {const msg = ref('hello,vue3');return {msg,};},
});
</script>//子组件
<template><h2>子组件</h2><h3>msg:{{ msg }}</h3>
</template><script lang='ts'>
import { defineComponent } from 'vue';
export default defineComponent({name: 'Child',props: ['msg'],setup(props, {attrs, slots, emit}) {console.log('props:', props);//msg: "hello,vue3"console.log('attrs:', attrs);//msg2: "哈哈哈"return {};},
});
</script>
复制代码

演示emit

//父组件
<template><child @show="show" />
</template><script lang='ts'>setup() {const show = () => {console.log('name:', 'hzw');};return {show,};},
</script>//子组件
<template><button @click='emitFn'>事件分发</button>
</template>
<script lang='ts'>
import { defineComponent } from 'vue';export default defineComponent({name: 'Child',setup(props, { emit }) {const emitFn = () => {emit('show');};return {emitFn,};},
});
</script>
复制代码

ref

作用

定义一个响应式的数据(一般用来定义一个基本类型的响应式数据UndefinedNullBooleanNumberString)

语法

const xxx = ref(initValue):
复制代码

注意script中操作数据需要使用xxx.value的形式,而模板中不需要添加.value

用一个例子来演示:实现一个按钮,点击可以增加数字

<template><div>{{count}}</div><button @click='updateCount'>增加</button>
</template>
复制代码

在Vue2中

data() {return {conunt: 0,};
},
methods: {updateCount() {this.conunt++;},
},
复制代码

在Vue3中

setup() {// ref用于定义一个响应式的数据,返回的是一个Ref对象,对象中有一个value属性//如果需要对数据进行操作,需要使用该Ref对象的value属性const count = ref(0);function updateCount() {count.value++;}return {count,updateCount,};},
复制代码

Vue2中我们通过this.$refs来获取dom节点,Vue3中我们通过ref来获取节点

首先需要在标签上添加ref='xxx',然后再setup中定义一个初始值为nullref类型,名字要和标签的ref属性一致

const xxx = ref(null)
复制代码

注意:一定要在setupreturn中返回,不然会报错。

还是用一个例子来演示:让输入框自动获取焦点

<template><h2>App</h2><input type="text">---<input type="text" ref="inputRef">
</template><script lang="ts">
import { onMounted, ref } from 'vue'
/*
ref获取元素: 利用ref函数获取组件中的标签元素
功能需求: 让输入框自动获取焦点
*/
export default {setup() {const inputRef = ref<HTMLElement|null>(null)onMounted(() => {inputRef.value && inputRef.value.focus()})return {inputRef}},
}
</script>
复制代码

reactive

语法

const proxy = reactive(obj)
复制代码

作用

定义多个数据的响应式,接收一个普通对象然后返回该普通对象的响应式代理器对象(Proxy),响应式转换是“深层的”:会影响对象内部所有嵌套的属性,所有的数据都是响应式的。

代码演示

<template><h3>姓名:{{user.name}}</h3><h3>年龄:{{user.age}}</h3><h3>wife:{{user.wife}}</h3><button @click="updateUser">更新</button>
</template>setup() {const user = reactive({name: 'hzw',age: 18,wife: {name: 'xioaohong',age: 18,books: ['红宝书', '设计模式', '算法与数据结构'],},});const updateUser = () => {user.name = '小红';user.age += 2;user.wife.books[0] = '金瓶梅';};return {user,updateUser,};},
复制代码

computed函数:

Vue2中的computed配置功能一致,返回的是一个ref类型的对象

计算属性的函数中如果只传入一个回调函数 表示的是get操作

import { computed } from 'vue';
const user = reactive({firstName: '韩',lastName: '志伟',
});
const fullName1 = computed(() => {return user.firstName + user.lastName;
});
return {user,fullName1,
};
复制代码

计算属性的函数中可以传入一个对象,可以包含setget函数,进行读取和修改的操作

const fullName2 = computed({get() {return user.firstName + '_' + user.lastName;},set(val: string) {const names = val.split('_');user.firstName = names[0];user.lastName = names[1];},
});
return {user,fullName2,
};
复制代码

watch函数:

Vue2中的watch配置功能一致,

  • 参数1:要监听的数据

  • 参数2:回调函数

  • 参数3:配置

作用

监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调

默认初始时不执行回调, 但可以通过配置immediatetrue, 来指定初始时立即执行第一次

通过配置deeptrue, 来指定深度监视

import { watch, ref } from 'vue';
const user = reactive({firstName: '韩',lastName: '志伟',
});
const fullName3 = ref('');
watch(user,({ firstName, lastName }) => {fullName3.value = firstName + '_' + lastName;},{ immediate: true, deep: true }
);
return {user,fullName3,
};
复制代码

watch监听多个数据,使用数组

watch监听非响应式数据的时候需要使用回调函数的形式

watch([()=>user.firstName,()=>user.lastName,fullName3],()=>{console.log('我执行了')})
复制代码

watchEffect函数:

作用

监视数据发生变化时执行回调,不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据,默认初始时就会执行第一次, 从而可以收集需要监视的数据。

import { watchEffect, ref } from 'vue';
const user = reactive({firstName: '韩',lastName: '志伟',
});
const fullName4 = ref('');
watchEffect(() => {fullName4.value = user.firstName + '_' + user.lastName;
});
return {user,fullName4,
};
watchEffect可以实现计算属性set方法
watchEffect(() => {const names = fullName3.value.split('_');user.firstName = names[0];user.lastName = names[1];
});
复制代码

生命周期对比:

微信截图_20210623104108.png

注意:3.0中的生命周期钩子要比2.X中相同生命周期的钩子要快

Composition API还新增了以下调试钩子函数:但是不怎么常用

  • onRenderTracked

  • onRenderTriggered

代码演示

setup() {onBeforeMount(() => {console.log('--onBeforeMount')})onMounted(() => {console.log('--onMounted')})onBeforeUpdate(() => {console.log('--onBeforeUpdate')})onUpdated(() => {console.log('--onUpdated')})onBeforeUnmount(() => {console.log('--onBeforeUnmount')})onUnmounted(() => {console.log('--onUnmounted')})
}
复制代码

toRefs

作用

把一个响应式对象转换成普通对象,该普通对象的每个属性都是一个 ref

应用

我们使用reactive创建的对象,如果想在模板中使用,就必须得使用xxx.xxx的形式,如果大量用到的话还是很麻烦的,但是使用es6解构以后,会失去响应式,那么toRefs的作用就体现在这,,利用toRefs可以将一个响应式 reactive 对象的所有原始属性转换为响应式的ref属性。当然小伙伴们可以自行开发更多应用场景。

代码演示

<template><div>name:{{name}}</div>
</template><script lang='ts'>
import { defineComponent, reactive, toRefs } from 'vue';export default defineComponent({name: '',setup() {const state = reactive({name: 'hzw',});const state2 = toRefs(state);setInterval(() => {state.name += '===';}, 1000);return {//通过toRefs返回的对象,解构出来的属性也是响应式的...state2,};},
});
</script>
复制代码

provide 与 inject

作用

实现跨层级组件(祖孙)间通信

代码演示

父组件

<template><h1>父组件</h1><p>当前颜色: {{color}}</p><button @click="color='red'">红</button><button @click="color='yellow'">黄</button><button @click="color='blue'">蓝</button><hr><Son />
</template>
<script lang="ts">
import { provide, ref } from 'vue'
import Son from './Son.vue'
export default {name: 'ProvideInject',components: {Son},setup() {const color = ref('red')provide('color', color)return {color}}
}
</script>
复制代码

子组件

<template><div><h2>子组件</h2><hr><GrandSon /></div>
</template><script lang="ts">
import GrandSon from './GrandSon.vue'
export default {components: {GrandSon},
}
</script>
复制代码

孙子组件

<template><h3 :style="{color}">孙子组件: {{color}}</h3>
</template><script lang="ts">
import { inject } from 'vue'
export default {setup() {const color = inject('color')return {color}}
}
</script>
复制代码

其他特性

Teleport(瞬移)

作用

Teleport 提供了一种干净的方法, 让组件的html在父组件界面外的特定标签(很可能是body)下插入显示 换句话说就是可以把 子组件 或者 dom节点 插入到任何你想插入到的地方去。

语法

使用to属性 引号内使用选择器

<teleport to="body"></teleport>
复制代码

代码演示

//父组件<template><div class="father"><h2>App</h2><modal-button></modal-button></div>
</template><script lang="ts">
import ModalButton from './components/ModalButton.vue'
export default {setup() {return {}},components: {ModalButton,},
}
</script>//子组件
<template><div class="son"><button @click="modalOpen = true">点我打开对话框</button><teleport to="body"><div v-if="modalOpen"class="looklook">看看我出现在了哪里<button @click="modalOpen = false">Close</button></div></teleport></div>
</template><script>
import { ref } from 'vue'
export default {name: 'modal-button',setup() {const modalOpen = ref(false)return {modalOpen,}},
}
</script>
复制代码

可以看到在子组件中的looklook元素跑到了body下面,而之前的位置默认出现了两行注释

微信截图_20210623170701.png

Suspense(不确定的)

作用

它们允许我们的应用程序在等待异步组件时渲染一些后备内容,可以让我们创建一个平滑的用户体验

语法

<Suspense><template v-slot:default><!-- 异步组件 --><AsyncComp /></template><template v-slot:fallback><!-- 后备内容 --><h1>LOADING...</h1></template></Suspense>
复制代码

vue3中引入异步组件的方式

const AsyncComp = defineAsyncComponent(() => import('./AsyncComp.vue'))
复制代码

代码演示

父组件

<template><Suspense><!-- v-slot:defaul可以简写成#defaul --><template v-slot:default><AsyncComp/></template><template v-slot:fallback><h1>LOADING...</h1></template></Suspense>
</template><script lang="ts">
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() => import('./AsyncComp.vue'))
export default {setup() {return {}},components: {AsyncComp,}
}
</script>
复制代码

子组件

<template><h2>AsyncComp22</h2><p>{{msg}}</p>
</template><script lang="ts">
export default {name: 'AsyncComp',setup () {return new Promise((resolve, reject) => {setTimeout(() => {resolve({msg: 'abc'})}, 2000)})}
}
</script>复制代码

通过下图可以看到在异步组件加载出来之前,显示的是fallback中的内容

16.gif

响应式数据的判断

作用

  • isRef: 检查一个值是否为一个 ref 对象

  • isReactive: 检查一个对象是否是由 reactive 创建的响应式代理

  • isReadonly: 检查一个对象是否是由 readonly 创建的只读代理

  • isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

代码演示

setup() {const state1 = ref(1);console.log('isref:', isRef(state1));//isref: trueconst state2 = reactive({});console.log('isReactive:', isReactive(state2));//isReactive: trueconst state3 = readonly({});console.log('isReadonly:', isReadonly(state3));//isReadonly: trueconst state4 = reactive({});console.log('isProxy:', isProxy(state2));//isProxy: trueconsole.log('isProxy:', isProxy(state4));//isProxy: truereturn {};},
复制代码

其他不常用特性

还有很多很多不常用的新特性,我在日常开发中是没有用到的,很多都是用来做优化的,感兴趣的小伙伴们自行去官网查看,或者大佬们可以介绍一下应用场景。

  • shallowReactive

  • shallowRef

  • readonly

  • shallowReadonly

  • markRaw

  • customRef

  • ...

语法糖

虽然Composition API用起来已经非常方便了,但是我们还是有很烦的地方,比如

  • 组件引入了还要注册

  • 属性和方法都要在setup函数中返回,有的时候仅一个return就十几行甚至几十行

  • ...

  • 不想写啊怎么办

好办,Vue3官方提供了script setup语法糖

只需要在script标签中添加setup,组件只需引入不用注册,属性和方法也不用返回,setup函数也不需要,甚至export default都不用写了,不仅是数据,计算属性和方法,甚至是自定义指令也可以在我们的template中自动获得。

但是这么过瘾的语法糖,还是稍微添加了一点点心智负担,因为没有了setup函数,那么propsemitattrs怎么获取呢,就要介绍一下新的语法了。

setup script语法糖提供了三个新的API来供我们使用:definePropsdefineEmituseContext

  • defineProps 用来接收父组件传来的值props

  • defineEmit 用来声明触发的事件表。

  • useContext 用来获取组件上下文context

代码演示

父组件

<template><div><h2>我是父组件!</h2><Child msg="hello"@child-click="handleClick" /></div>
</template><script setup>
import Child from './components/Child.vue'const handleClick = (ctx) => {console.log(ctx)
}
</script>
复制代码

子组件

<template><span @click="sonClick">msg: {{ props.msg }}</span>
</template><script setup>
import { useContext, defineProps, defineEmit } from 'vue'const emit = defineEmit(['child-click'])
const ctx = useContext()
const props = defineProps({msg: String,
})const sonClick = () => {emit('child-click', ctx)
}
</script>复制代码

我们点击一下子组件可以看到context被打印了出来,其中的attrsemitslotsexpose属性和方法依然可以使用。props也可以输出在页面上,事件也成功派发。

其他知识点

接下来介绍一下我使用Vue3过程中遇到的问题或者小技巧,不全面,想起什么就写什么吧

script setup语法糖请注意

如果在父组件中通过ref='xxx'的方法来获取子组件实例,子组件使用了script setup语法糖,那么子组件的数据需要用expose的方式导出,否则会因为获取不到数据而报错。

代码演示

父组件

<template><div><h2>我是父组件!</h2><Child ref='son' /></div>
</template><script setup>
import Child from './components/Child.vue'
import { ref } from 'vue'
const son = ref(null)
console.log('												

整理的一些 Vue3 知识点相关推荐

  1. 整理的一些 Vue3 知识点,初学者看完就能上手做项目

    点击上方关注 前端技术江湖,一起学习,天天进步 看完你就基本可以上手搞开发了,本文适合Vue初学者,或者Vue2迁移者,当然还是建议Vue3官网完全过一遍.不适合精通原理,源码的大佬们. 先推荐两个v ...

  2. 敏捷ACP 常用关键词整理 敏捷ACP 常用知识点整理

    敏捷ACP 常用关键词整理   敏捷ACP 常用知识点整理 一.MoSCoW 1.MoSCoW : 读作"莫斯科",适用于故事优先级的排序,首次出现在 3-13敏捷产品实践:产品待 ...

  3. 熬夜整理两万字Python知识点

    熬夜整理两万字Python知识点 第一章 变量和简单数据类型 1.1 变量 1.2 字符串 1.2.1 使用方法修改字符串大小 1.3 数 第二章 列表 2.1 列表概念 2.2 列表的相关操作 2. ...

  4. vue3知识点:provide 与 inject

    文章目录 三.其它 Composition API(不常用,了解即可) 5.provide 与 inject 测试案例 完整代码 本人其他相关文章链接 三.其它 Composition API(不常用 ...

  5. 持续不断更新中... 自己整理的一些前端知识点以及前端面试题,包括vue2,vue3,js,ts,css,微信小程序等

    Vue3自考题 1,如何使用vue3的组合式api 答: 在普通的前端项目工程中,在script标签中增加setup即可使用api 使用setup()钩子函数 2,computed 与各个watch之 ...

  6. python基础知识整理-python入门基础知识点整理-20171214

    一.知识点整理 1.python2与python3的区别: (1)宏观比对 python2 源码不标准,较为混乱,并且重复的代码很多. python3 源码统一了标准,同时也去除了重复代码. (2)编 ...

  7. python基础知识整理-python爬虫基础知识点整理

    首先爬虫是什么? 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本. 根据我的经验,要学习Python爬虫 ...

  8. 七万字,151张图,通宵整理消息队列核心知识点总结!这次彻底掌握MQ!

    前言 本文主要涵盖了关于消息队列的大部分核心知识点,涉及的消息队列有 RocketMQ.Kafka. 本文很长,所有内容都为博主原创,纯手打,如果觉得不错的话,来个点赞评论收藏三连呀! 之后还会有迭代 ...

  9. 学习 C 语言看这一篇就够了!吐血整理 C 语言所有知识点

    C 语言的知识点汇总 文中的图片上有我公众号的水印,我本来也不想加,因为图片是很早之前做的.本来也可以不用加,但是我感觉加上更有利于读者理解知识点,希望审核大大不要限流. 兄弟们,为了你们,我也是拼了 ...

最新文章

  1. PCL滤波介绍(2)
  2. winform 让他间隔一段时间 执行事件 且只执行一次_Redis 事件机制详解
  3. 更灵活的定位内存地址的方法02 - 零基础入门学习汇编语言33
  4. Hibernate一对一映射示例注释
  5. 写给即将过去的2012
  6. SilverLight中的数据绑定
  7. json 来实现 php 与 javascript,用 Json 来实现 PHP 与 JavaScript 间数据交换
  8. python数据类型-列表练习
  9. 创作原创歌词的韵律十三辙与韵脚押韵方法
  10. 14款超实用的Unity3D常用插件推荐
  11. java+mysql学科竞赛管理系统(java,web)
  12. IMDB TOP250中文版(截止2011.6.18)
  13. 解决vmware虚拟机安装ubuntu 无法连接wifi找不到wifi适配器问题
  14. 字母金字塔(类同数字金字塔)
  15. 苹果系统Fn键怎样使用?
  16. php打印马赛克,PHP-如何用PHP给一张图生成马赛克效果?
  17. navigation_plugin
  18. 天龙八部服务器端Lua脚本系统
  19. python爬虫实现boss直聘自动化强制投简历
  20. 国科大学习资料--最优化计算方法(王晓)--期末考试试卷1

热门文章

  1. 递归、迭代和分治(2):递归的典型例子
  2. 新冠肺炎疫情数据爬取以及几种简单的地图可视化方法
  3. [Power BI] 认识Power Query和M语言
  4. linux c 编译 未定义的引用,c – Linux makefile中的未定义引用
  5. 中职学生计算机学情分析报告,中职学生学情分析及对策
  6. STM32的四种开发方式
  7. acm国家集训队论文(1999-2009)
  8. 基于51单片机的酒精浓度检测仪设计
  9. 【分享】性能比肩美拍秒拍的Android视频录制编辑特效解决方案【1】
  10. SQL优化工具分享-SQL Tuning Expert Pro for Oracle Trial