vue框架介紹及語法

一、什麼是Vue?
爲了實現前後端分離的開發理念,開發前端 SPA(single page web application) 項目,實現數據綁定,路由配置,項目編譯打包等一系列工作的技術框架。
二、如何使用?
直接下載vue.js引入到網頁中即可。
Vue.js 官網下載地址:http://vuejs.org/guide/installation.html
三、基礎語法:
1、雙向綁定:
數據綁定最常見的形式就是使用 {{...}}(雙大括號)的文本插值
html:
<div id="app">
<p>{{message}}</p>
<input v-model="message"/>
</div>
js:
new Vue({
el:'#app',
data:{
message:'Hello vue.js'
}
})
2、渲染列表
html:
<div id="app">
<ul>
<li v-for="todo in todos">{{todo.text}}</li>
</ul>
</div>
js:
new Vue({
el:'#app',
data:{
todos:[
{text:'學習vue'},
{text:'學習Sass'},
{text:'學習webpack'}
]
}
})
3、處理用戶輸入
html:
<div id="app">
<p>{{message}}</p>
<input v-model='message'/>
<button type="button" v-on:click="reverseMessage">反轉</button>
</div>
js:
new Vue({
el:'#app',
data:{
message:'hello world'
},
methods:{
reverseMessage:function(){
this.message=this.message.split('').reverse().join('')
}
}
})
4、插值
html:
<div id="app">
<!-- 單次文本插值 -->
<p>{{*message}}</p>
<!-- 解析真的html字符串 -->
<p>{{{raw_html}}}</p>
<!-- html特性 -->
<p id="item-{{id}}">html特性</p>
</div>
js:
new Vue({
el:'#app',
data:{
message:'Hello vue.js',
raw_html:'<span>原始的html</span>',
id:'1'
}
})
5、綁定表達式
html:
<div id="app">
<!-- javascript表達式 -->
<p>{{number+1}}</p>
<p>{{ok ? 'Yes' : 'No'}}</p>
<p>{{message.split('').reverse().join('')}}</p>
<!-- 過濾器 -->
<p>{{name | capitalize}}</p>
</div>
js:
new Vue({
el:'#app',
data:{
number:2,
ok:false,
message:'123456789',
name:'brucee lee'
}
})
6、指令
html:
<div id="app">
<!-- 參數 -->
<a v-bind:href="url" v-on:click="dosomething">指令帶參數</a>
<!-- v-bind、v-on縮寫 -->
<a :href="url" @click="dosomething">指令縮寫</a>
</div>
js:
new Vue({
el:'#app',
data:{
url:'http://g.pptv.com'
},
methods:{
dosomething:function(){
alert(this.url);
}
}
})
7、計算屬性
html:
<div id="app">
<p>a={{a}},b={{b}}</p>
<p>{{fullName}}</p>
</div>
js:
new Vue({
el:'#app',
data:{
a:1,
firstName:'Micro',
lastName:'Jodon'
},
computed:{
b:function(){
return this.a + 1;
},
/*fullName:function(){
return this.firstName + ' ' + this.lastName;
}*/
fullName:{
get:function(){
return this.firstName + ' ' + this.lastName;
},
set:function(newValue){
var names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[names.length-1];
}
}
}
})
9)class與style綁定
[css] view plain copy
.static{
width: 200px;
margin: 20px auto;
height: 25px;
line-height: 25px;
text-align: center;
font-size: 18px;
}
.class-a{
background-color: #f00;
}
.class-b{
color: #fff;
}
.class-c{
padding: 5px 0;
}
[html] view plain copy
<div id="app">
<!-- 綁定class:對象語法 -->
<p class="static" v-bind:class="{'class-a':isA,'class-b':isB}">綁定class</p>
<p class="static" v-bind:class="classObject">綁定class</p>
<!-- 綁定class:數組語法 -->
<p class="static" v-bind:class="[classA,classB,classC]">綁定class</p>
<p class="static" v-bind:class="[classA,{ 'class-b': isB,'class-c': isC}]">綁定class</p>
<!-- 綁定style:對象語法 -->
<p class="static" v-bind:style="styleObject">綁定style</p>
<!-- 綁定style:數組語法 -->
<p class="static" v-bind:style="[styleObjectA,styleObjectB]">綁定style</p>
</div>
[javascript] view plain copy
new Vue({
el:'#app',
data:{
classA:'class-a',
classB:'class-b',
classC:'class-c',
isA:true,
isB:false,
isC:true,
classObject:{
'class-a':true,
'class-b':true
},
styleObject:{
color:'red',
fontSize:'13px',
backgroundColor:'#00f'
},
styleObjectA:{
color:'green',
fontSize:'16px'
},
styleObjectB:{
backgroundColor:'#f0f',
transform:'rotate(7deg)'
}
}
})
10)條件渲染
[html] view plain copy
<div id="app">
<h1 v-if="Math.random() > 0.5">對不起!</h1>
<h1 v-else>沒關係</h1>
<template v-if="ok">
<h1>標題</h1>
<p>段落1</p>
<p>段落2</p>
</template>
<h1 v-show="isShow">Hello!</h1>
<custom-component v-show="condition"></custom-component>
<p v-show="!condition">這可能也是一個組件</p>
</div>
[javascript] view plain copy
// 定義
var MyComponent = Vue.extend({
template: '<div>A custom component!</div>'
});
// 註冊
Vue.component('custom-component', MyComponent);
new Vue({
el:'#app',
data:{
ok:true,
isShow:false,
condition:true
},
})
11)列表渲染
[html] view plain copy
<div id="app">
<!-- 數組v-for -->
<ul>
<template v-for="item in items" track-by="_uid">
<li>{{ parentMessage }} - {{ $index }} - {{ item.message }}</li>
<li class="divider"></li>
</template>
</ul>
<!-- 對象v-for -->
<ul>
<li v-for="(key,val) in object">{{key}} : {{val}}</li>
</ul>
<!-- 值域v-for -->
<span v-for="n in 10">{{ n }}</span>
</div>
[css] view plain copy
ul{
list-style: none;
width: 150px;
}
.divider{
height: 2px;
background-color: #00f;
}
span{
padding: 0 2px;
}
[javascript] view plain copy
var vm=new Vue({
el:'#app',
data:{
parentMessage:'水果',
items:[
{ _uid:'001',message:'香蕉'},
{ _uid:'002',message:'橘子'}
],
object:{
FirstName: 'John',
LastName: 'Doe',
Age: 30
}
}
});
//變異方法:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
vm.items.push({message:'蘋果'},{message:'梨子'});//推入兩項
vm.items.shift();//取出第一項
//非變異方法:filter(), concat(), slice(),可用替換數組來修改原數組
vm.items=vm.items.filter(function (item) {
return item.message.match(/子/);
})
12)方法與事件處理器
[html] view plain copy
<div id="app">
<!-- 內聯語句處理器 -->
<button type="button" v-on:click="say('Hello',$event)">提交</button>
<!-- 事件修飾符 -->
<!-- 阻止單擊事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修飾符可以串聯 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件偵聽器時使用 capture 模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只當事件在該元素本身(而不是子元素)觸發時觸發回調 -->
<div v-on:click.self="doThat">...</div>
<!-- 按鍵修飾符 -->
<input v-on:keyup.enter="submit">
</div>
[javascript] view plain copy
var vm=new Vue({
el:'#app',
methods:{
say:function(msg,event){
alert(msg+","+event.target.tagName);
event.preventDefault();
}
}
});
13)表單控件綁定
[html] view plain copy
<div id="app">
<!-- 多行文本 -->
<span>這是您的評論:</span>
<p>{{message}}</p>
<textarea v-model="message" placeholder="請輸入您的評論"></textarea>
<br>
<!-- 單選框 -->
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
<br>
<!-- 多個單選框 -->
<input type="checkbox" id="jack" value="馬雲" v-model="checkedNames">
<label for="jack">馬雲</label>
<input type="checkbox" id="john" value="馬化騰" v-model="checkedNames">
<label for="john">馬化騰</label>
<input type="checkbox" id="mike" value="李彥宏" v-model="checkedNames">
<label for="mike">李彥宏</label>
<br>
<span>選中的值: {{ checkedNames | json }}</span>
<br>
<!-- 單選鈕 -->
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>選中的值: {{ picked }}</span>
<br>
<!-- 下拉列表單選 -->
<select v-model="selected">
<option selected>湖北</option>
<option>北京</option>
<option>上海</option>
</select>
<span>選中的值: {{ selected }}</span>
<br>
<!-- 下拉列表多選 -->
<select v-model="selecteds" multiple>
<option v-for="option in options" v-bind:value="option.value">{{ option.text }}</option>
</select>
<br>
<span>選中的值: {{ selecteds | json }}</span>
<br>
<!--綁定動態值到Vue實例-->
<!-- 選中時爲a,未選中時爲b -->
<input type="checkbox" v-model="toggle" v-bind:true-value="a" v-bind:false-value="b"/>
<span>選中時的值:{{toggle}}</span>
<br>
<input type="radio" v-model="pick" v-bind:value="c">男
<input type="radio" v-model="pick" v-bind:value="d">女
<span>選中時的值:{{pick}}</span>
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model="msg" lazy>
<!-- 設置轉換爲數值類型 -->
<input v-model="age" number>
<!-- 設置延時 -->
<input v-model="msg" debounce="500">
</div>
[javascript] view plain copy
var vm=new Vue({
el:'#app',
data: {
checkedNames: [],
options:[
{text:'南京',value:'南京'},
{text:'蘇州',value:'蘇州'},
{text:'無錫',value:'無錫'}
],
a:'選中',
b:'未選中',
c:'男',
d:'女'
}
});
14)css過渡
[html] view plain copy
<div id="app">
<div v-if="show" transition="expand">Hello1</div>
<div v-if="show" :transition="transitionName">Hello2</div>
<button type="button" v-on:click="toggle">過渡效果演示</button>
</div>
[javascript] view plain copy
/* 必需 */
.expand-transition {
transition: all 0.5s ease;
height: 30px;
padding: 10px;
background-color: #eee;
overflow: hidden;
}
/* .expand-enter 定義進入的開始狀態 */
/* .expand-leave 定義離開的結束狀態 */
.expand-enter, .expand-leave {
height: 0;
padding: 0 10px;
opacity: 0;
}
.fade-transition{
transition: all 0.5s ease;
height: 30px;
padding: 10px;
background-color: #2df;
overflow: hidden;
}
.fade-enter, .fade-leave {
padding: 0 10px;
opacity: 0.5;
}
[javascript] view plain copy
var vm=new Vue({
el:'#app',
data: {
show:true,
transitionName:'fade'
},
methods:{
toggle:function(){
if(this.show){
this.show=false;
}else{
this.show=true;
}
}
},
transitions: {
expand: {
beforeEnter: function (el) {
el.textContent = 'beforeEnter'
},
enter: function (el) {
el.textContent = 'enter'
},
afterEnter: function (el) {
el.textContent = 'afterEnter'
},
beforeLeave: function (el) {
el.textContent = 'beforeLeave'
},
leave: function (el) {
el.textContent = 'leave'
},
afterLeave: function (el) {
el.textContent = 'afterLeave'
}
}
}
});
15)css自定義過渡(注:與animats.css配合使用)
[html] view plain copy
<div id="app">
<div v-show="ok" class="animated" transition="bounce">只有我最搖擺</div>
<button type="button" v-on:click="toggle">演示過渡效果</button>
</div>
[css] view plain copy
.animated{
width: 150px;
background-color: #2df;
height: 30px;
padding: 10px;
}
[javascript] view plain copy
var vm=new Vue({
el:'#app',
data: {
ok:true
},
methods:{
toggle:function(){
if(this.ok){
this.ok=false;
}else{
this.ok=true;
}
}
},
transitions: {
bounce: {
enterClass: 'bounceInLeft',
leaveClass: 'bounceOutRight'
}
}
});
16)CSS動畫(注:與animats.css配合使用)
[html] view plain copy
<div id="app">
<div v-show="ok" class="animated" transition="bounce">看我變一個</div>
<button type="button" v-on:click="toggle">演示動畫效果</button>
</div>
[css] view plain copy
.animated{
width: 150px;
background-color: #2df;
height: 30px;
padding: 10px;
}
.bounce-transition {
display: inline-block; /* 否則 scale 動畫不起作用 */
}
.bounce-enter {
animation: bounce-in .5s;
}
.bounce-leave {
animation: bounce-out .5s;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
@keyframes bounce-out {
0% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(0);
}
}
[javascript] view plain copy
var vm=new Vue({
el:'#app',
data: {
ok:true
},
methods:{
toggle:function(){
if(this.ok){
this.ok=false;
}else{
this.ok=true;
}
}
}
});
17)Javascript過渡
[html] view plain copy
<div id="app">
<p transition='fade'>什麼和什麼?</p>
</div>
[css] view plain copy
.fade-transition{
transition: all 0.5s ease;
height: 30px;
padding: 10px;
background-color: #2df;
overflow: hidden;
}
[javascript] view plain copy
var vm=new Vue({
el:'#app'
});
vm.transition('fade', {
css: false,
enter: function (el, done) {
// 元素已被插入 DOM
// 在動畫結束後調用 done
$(el)
.css('opacity', 0)
.animate({ opacity: 1 }, 1000, done)
},
enterCancelled: function (el) {
$(el).stop()
},
leave: function (el, done) {
// 與 enter 相同
$(el).animate({ opacity: 0 }, 1000, done)
},
leaveCancelled: function (el) {
$(el).stop()
}
})
18)漸進過渡
[html] view plain copy
<div id="example-1">
<input v-model="query">
<ul>
<li v-for="item in list | filterBy query" transition="staggered" stagger="100">
{{item.msg}}
</li>
</ul>
</div>
[css] view plain copy
#example-1{
width:200px;
margin:20px auto;
font-size:14px;
color:#ff6600;
}
ul {
padding-left: 0;
font-family: Helvetica, Arial, sans-serif;
}
.staggered-transition {
transition: all .5s ease;
overflow: hidden;
margin: 0;
height: 25px;
}
.bounceInLeft, .bounceOutRight {
opacity: 0;
height: 0;
}
[javascript] view plain copy
var exampleData={
query: '',
list: [
{ msg: 'Bruce Lee' },
{ msg: 'Jackie Chan' },
{ msg: 'Chuck Norris' },
{ msg: 'Jet Li' },
{ msg: 'Kung Fury' }
]
};
var exampleVM = new Vue({
el:'#example-1',
data:exampleData,
transitions:{
staggered:{
enterClass:'bounceInLeft',
leaveClass: 'bounceOutRight'
}
}
});
/* exampleVM.transition('stagger', {
stagger: function (index) {
// 每個過渡項目增加 50ms 延時
// 但是最大延時限制爲 300ms
return Math.min(300, index * 50)
}
})*/
19)組件
[html] view plain copy
<div id="example">
<my-component></my-component>
</div>
[javascript] view plain copy
//定義
/*var myComponent=Vue.extend({
template:'<div>A custom component!</div>'
});*/
//註冊
//Vue.component('my-component',myComponent);
//在一個步驟中定義與註冊
Vue.component('my-component',{
template:'<div>A custom component!</div>'
});
//創建根實例
new Vue({
el:'#example'
});
20)組件局部註冊
[html] view plain copy
<div id="example">
<parent-component></parent-component>
</div>
[javascript] view plain copy
//定義
/*var Child=Vue.extend({
template:'<div>A child component!</div>'
});*/
var Parent=Vue.extend({
template:'<div>A parent component!<my-component></my-component></div>',
components:{
// <my-component> 只能用在父組件模板內
'my-component':{
template:'<div>A child component!</div>'
}
}
});
// 註冊父組件
Vue.component('parent-component', Parent);
//創建根實例
new Vue({
el:'#example'
});
21)使用props傳遞數據
[html] view plain copy
<div id="example" class="demo">
<input type="text" v-model="parentMessage"/><br>
<child v-bind:my-message="parentMessage"></child>
<!-- 雙向綁定 -->
<child :msg.sync="parentMessage"></child>
<!-- 單次綁定 -->
<child :msg.once="parentMessage"></child>
</div>
[css] view plain copy
.demo{
border: 1px solid #eee;
border-radius: 2px;
padding: 25px 35px;
margin-bottom: 40px;
font-size: 1.2em;
line-height: 1.5em;
}
[javascript] view plain copy
new Vue({
el:'#example',
data:{
parentMessage:'Message from parent'
},
components:{
child:{
props:['myMessage'],
template:'<span>{{myMessage}}</span>'
}
}
});
22)prop驗證
[html] view plain copy
<div id="example" class="demo">
<child></child>
</div>
[css] view plain copy
.demo{
border: 1px solid #eee;
border-radius: 2px;
padding: 25px 35px;
margin-bottom: 40px;
font-size: 1.2em;
line-height: 1.5em;
}
[javascript] view plain copy
new Vue({
el:'#example',
components:{
child:{
props: {
// 基礎類型檢測 (`null` 意思是任何類型都可以)
propA: Number,
// 多種類型 (1.0.21+)
propM: [String, Number],
// 必需且是字符串
propB: {
type: String,
required: true
},
// 數字,有默認值
propC: {
type: Number,
default: 100
},
// 對象/數組的默認值應當由一個函數返回
propD: {
type: Object,
default: function () {
return { msg: 'hello' }
}
},
// 指定這個 prop 爲雙向綁定
// 如果綁定類型不對將拋出一條警告
propE: {
twoWay: true
},
// 自定義驗證函數
propF: {
validator: function (value) {
return value > 10
}
},
// 轉換函數(1.0.12 新增)
// 在設置值之前轉換值
propG: {
coerce: function (val) {
return val + ''; // 將值轉換爲字符串
}
},
propH: {
coerce: function (val) {
return JSON.parse(val); // 將 JSON 字符串轉換爲對象
}
}
},
template:'<span>hello world!</span>'
}
}
});
23)父子組件通信
[html] view plain copy
<!--子組件模板-->
<template id="child-template">
<input type="text" v-model="msg"/>
<button type="button" v-on:click="notify">派發事件</button>
</template>
<!--父組件模板-->
<div id="events-example" class="demo">
<p>Messages:{{ messages | json }}</p>
<child v-on:child-msg="handleIt"></child>
</div>
[css] view plain copy
.demo{
border: 1px solid #eee;
border-radius: 2px;
padding: 25px 35px;
margin-bottom: 40px;
font-size: 1.2em;
line-height: 1.5em;
}
[javascript] view plain copy
// 註冊子組件,將當前消息派發出去
Vue.component('child',{
template:'#child-template',
data:function(){
return {msg:'hello'}
},
methods:{
notify:function(){
if(this.msg.trim()){
this.$dispatch('child-msg',this.msg);
this.msg='';
}
}
}
});
// 初始化父組件,收到消息時將事件推入一個數組
var parent=new Vue({
el:'#events-example',
data:{
messages:[]
},
methods:{
handleIt:function(msg){
this.messages.push(msg);
}
}
// 在創建實例時 `events` 選項簡單地調用 `$on`
/*events:{
'child-msg':function(msg){
this.messages.push(msg);
}
}*/
})
24)自定義指令-基礎
[html] view plain copy
<div id="demo" v-demo:hello.a.b="msg"></div>
[javascript] view plain copy
Vue.directive('demo', {
bind: function () {
console.log('demo bound!')
},
update: function (value) {
this.el.innerHTML =
'name - ' + this.name + '<br>' +
'expression - ' + this.expression + '<br>' +
'argument - ' + this.arg + '<br>' +
'modifiers - ' + JSON.stringify(this.modifiers) + '<br>' +
'value - ' + value
}
});
var demo = new Vue({
el: '#demo',
data: {
msg: 'hello!'
}
})
25)自定義指令-高級選項
[html] view plain copy
<div id="demo" >
<!--對象字面量-->
<div v-demo-1="{ color: 'white', text: 'hello!' }"></div>
<!--字面修飾符-->
<div v-demo-2.literal="foo bar baz"></div>
<!--元素指令-->
<my-directive></my-directive>
<!--高級選項-params-->
<div v-example a="hi"></div>
</div>
[javascript] view plain copy
Vue.directive('demo-1', function(value){
console.log(value.color);
console.log(value.text);
});
Vue.directive('demo-2',function(value){
console.log(value);
});
Vue.elementDirective('my-directive',{
bind:function(){
console.log(this.el);
}
});
Vue.directive('example',{
params:['a'],
bind:function(){
console.log(this.params.a);
}
});
Vue.directive('two', {
twoWay: true,
bind: function () {
this.handler = function () {
// 將數據寫回 vm
// 如果指令這樣綁定 v-example="a.b.c"
// 它將用給定值設置 `vm.a.b.c`
this.set(this.el.value)
}.bind(this);
this.el.addEventListener('input', this.handler);
},
unbind: function () {
this.el.removeEventListener('input', this.handler)
}
});
vm=new Vue({
el: '#demo'
});
26)自定義過濾器
[html] view plain copy
<div id="demo" class="demo">
<!--基礎過濾器-->
<span v-text="message | reverse"></span><br>
<span v-text="message | wrap 'before' 'after'"></span><br>
<!--雙向過濾器-->
<input type="text" v-model="money | currencyDisplay"/>
<p>ModelValue:{{money | currencyDisplay}}</p>
<!--動態參數-->
<input v-model="userInput"/>
<span>{{msg | concat userInput}}</span>
</div>
[css] view plain copy
.demo{
border: 1px solid #eee;
border-radius: 2px;
padding: 25px 35px;
margin-bottom: 40px;
font-size: 1.2em;
line-height: 1.5em;
}
[javascript] view plain copy
Vue.filter('reverse',function(value){
return value.split('').reverse().join('');
});
Vue.filter('wrap',function(value,begin,end){
return begin+' '+value+' '+end;
});
Vue.filter('currencyDisplay',{
// model -> view
// 在更新 `<input>` 元素之前格式化值
read:function(val){
return '$'+val.toFixed(2)
},
// view -> model
// 在寫回數據之前格式化值
write: function(val, oldVal) {
var number = +val.replace(/[^\d.]/g, '')
return isNaN(number) ? 0 : parseFloat(number.toFixed(2))
}
});
Vue.filter('concat',function(value,input){
return value+input;
})
new Vue({
el:'#demo',
data:{
message:'abc',
money:123.45,
msg:'hello',
userInput:'hi'
}
});
27)混合
[html] view plain copy
<div id="demo" class="demo">
</div>
[css] view plain copy
.demo{
border: 1px solid #eee;
border-radius: 2px;
padding: 25px 35px;
margin-bottom: 40px;
font-size: 1.2em;
line-height: 1.5em;
}
[javascript] view plain copy
var myMixin={
created:function(){
this.hello();
},
methods:{
hello:function(){
console.log('hello from mixin!');
}
}
};
// 定義一個組件,使用這個混合對象
var Component = Vue.extend({
mixins: [myMixin]
});
var component = new Component();
new Vue({
el:'#demo'
});
28)混合-選項合併
[html] view plain copy
<div id="demo" class="demo">
</div>
[css] view plain copy
.demo{
border: 1px solid #eee;
border-radius: 2px;
padding: 25px 35px;
margin-bottom: 40px;
font-size: 1.2em;
line-height: 1.5em;
}
[javascript] view plain copy
var mixin={
created:function(){
console.log('mixin hook called');
},
methods: {
foo: function () {
console.log('foo');
},
conflicting: function () {
console.log('from mixin');
}
}
};
var vm=new Vue({
el:'#demo',
mixins:[mixin],
created:function(){
console.log('component hook called');
},
methods:{
bar: function () {
console.log('bar');
},
conflicting: function () {
console.log('from self');
}
}
});
vm.foo();
vm.bar();
vm.conflicting();//組件優先

參考資料:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章