我的Vue學(xué)習(xí)筆記

Vue安裝

安裝腳手架寇钉,使用全局安裝就可以

npm install -g @vue/cli

安裝完使用這個(gè)命令查看vue cli的版本

vue -V

初始化一個(gè)Vue項(xiàng)目

vue create lk-demo

然后會(huì)進(jìn)入一大堆的選項(xiàng)

1. Manually select features
2. 空格選擇咧织,A全選,手動(dòng)配置

運(yùn)行項(xiàng)目

npm run serve

將項(xiàng)目打包到dist目錄

npm run build

如果只有配置文件臼朗,那么需要手動(dòng)安裝依賴才能運(yùn)行

npm install

Vue指令

雙括號(hào)表達(dá)式{{intro}}

  1. 可以直接展示出data中的數(shù)據(jù)
  2. 還可以對(duì)數(shù)據(jù)進(jìn)行一些字符串的操作:{{intro.toUpperCase()}}
  3. 注意雙括號(hào)表達(dá)式是寫(xiě)在兩個(gè)標(biāo)簽中間的,這意味著你可以將它與其它字符進(jìn)行拼接

v-text

  1. v-text是一個(gè)屬性,如果倪同時(shí)還在兩個(gè)標(biāo)簽中間寫(xiě)上其它字符视哑,其它字符并不會(huì)顯示出來(lái)
  2. 僅僅是純文本绣否,data中的數(shù)據(jù)會(huì)被完完整整地展示出來(lái)

v-html

  1. data中的數(shù)據(jù)會(huì)以html的形式展示出來(lái)

v-bind

這些指令都不需要在雙引號(hào)內(nèi)部寫(xiě)雙括號(hào)表達(dá)式

v-bind:href

  1. 作用就是給HTML標(biāo)簽綁定某個(gè)屬性,該屬性在data里面:v-bind:href="site"
  2. 可以簡(jiǎn)寫(xiě)為::href="site"

v-bind:class

<div :class="oneClass">樣式類可以是字符串</div>
<div :class="{classOne: true, classTwo: true}">樣式類可以是對(duì)象</div>
<div :class="['classOne', 'classTwo']">樣式類可以是數(shù)組</div>
<div :class="[oneClass, twoClass]">樣式類可以是數(shù)組</div>
  1. 如果是字符串挡毅,那么引號(hào)里的是data里的屬性
  2. 如果是對(duì)象蒜撮,對(duì)象里的就是樣式表里的選擇器
  3. 如果是數(shù)組,數(shù)組里的字符串也是樣式表里的選擇器
  4. 同樣是數(shù)組跪呈,但是數(shù)組里不是字符串段磨,那就可以寫(xiě)data里的數(shù)據(jù)

v-bind:style

<div
style="width: 300px; height: 200px; margin: 10px auto;"
:style="{backgroundColor: bgColor, fontSize: fSize}">樣式類可以是字符串</div>
  1. v-bind:style的方式同樣可以給元素綁定樣式,只不過(guò)是內(nèi)聯(lián)樣式耗绿。
  2. 注意屬性名采用駝峰命名法薇溃,屬性實(shí)在data中定義的。

v-on:click

  1. 就是給該元素綁定某個(gè)methods中的事件
  2. 可以不傳遞參數(shù):v-on:click="study"缭乘,也可以傳遞參數(shù)@click="study('小撩')"
  3. 當(dāng)然沐序,你應(yīng)該也看出來(lái)了,它可以簡(jiǎn)寫(xiě):@click="study"
  4. 傳遞參數(shù)之后堕绩,用什么來(lái)接收參數(shù)呢策幼?首先方法里面的形參一定是有的,方法里面奴紧,可以用${name}特姐,來(lái)接收參數(shù)。
  5. <button @click="flag = !flag">切換</button>黍氮,@click不僅可以用來(lái)綁定函數(shù)唐含,還可以直接把方法寫(xiě)在里面。
study(name){
    alert(`${name},祝你學(xué)有所成沫浆!`);
}

v-model

  1. 該指令的作用就是將它所綁定的數(shù)據(jù)和data中的數(shù)據(jù)實(shí)現(xiàn)一個(gè)雙向綁定捷枯,實(shí)時(shí)互通。
  2. 用法就是:v-model="msg"

v-if

<div v-if="flag">今晚要上課专执!</div>
<div v-else>今晚不上課淮捆!</div>
  1. v-if還有與之配套的v-else
  2. v-if并不是通過(guò)設(shè)置css屬性display完成隱藏的

v-show

<div v-show="flag">今晚講Vue!</div>
<div v-show="!flag">今晚不講Vue本股!</div>
  1. 是通過(guò)設(shè)置display: none;來(lái)隱藏元素的攀痊。因此如果需要頻繁進(jìn)行顯示、隱藏操作的話拄显,它是比v-if更好的選擇苟径。

v-for

遍歷數(shù)組

<ul>
    <li v-for="(person, index) in persons" :key="personsKeys[index]">
        ID: {{personsKeys[index]}} ---- {{index}} ) 姓名:{{person.name}}, 年齡:{{person.age}}, 性別:{{person.sex}}
    </li>
</ul>
  1. v-for應(yīng)該用在li標(biāo)簽而不是ul標(biāo)簽上
  2. 注意括號(hào)里的第一個(gè)參數(shù)就相當(dāng)于數(shù)組里的每一項(xiàng),使用它就可以用對(duì)象的付出調(diào)用其各個(gè)數(shù)據(jù)

注意:這里還涉及到shortid的使用

  1. 安裝shortidnpm i shortid --save

  2. 在該組件中導(dǎo)入:import shortId from 'shortid'

  3. 在data中要有personsKeys這個(gè)數(shù)據(jù)躬审,它是一個(gè)空的數(shù)組

  4. 注意要添加一個(gè)mounted掛載點(diǎn)棘街,調(diào)用shortid自動(dòng)產(chǎn)生一個(gè)隨機(jī)數(shù)作為id

mounted() {
    this.personsKeys = this.persons.map(v=>shortId.generate())
}
  1. 然后就可以如上面代碼部分那樣使用了
  2. v-for可能需要使用:key這個(gè)屬性蟆盐,不然的話可能在控制臺(tái)會(huì)報(bào)警告

遍歷對(duì)象

<ul>
    <li v-for="(item, key) in persons[0]">
        {{key}} --- {{item}}
    </li>
</ul>
  1. key就是對(duì)象的key
  2. item相當(dāng)于對(duì)象的value

其它指令

v-pre

<p v-pre>{{intro}}</p>
  1. 貌似加了這個(gè)屬性之后,雙括號(hào)表達(dá)式就不會(huì)解析了蹬碧,而會(huì)被當(dāng)作純文本展示在頁(yè)面上。
  2. 它并不需要參數(shù)

v-cloak

<p v-cloak>{{message}}</p>
  1. 當(dāng)某些情況下炒刁,Vue加載有點(diǎn)慢恩沽,這個(gè)時(shí)候可能就會(huì)以源碼的形式展示出來(lái),比如這里的雙括號(hào)表達(dá)式翔始,這個(gè)時(shí)候使用v-cloak就可以避免這個(gè)閃爍問(wèn)題罗心。

v-once

<p v-once>{{name}}</p>
  1. 它會(huì)使得雙括號(hào)表達(dá)式僅解析一次,之后即便通過(guò)v-model改變了data中的數(shù)據(jù)也不會(huì)更新

ref的使用

<p ref="fish">我是一只魚(yú)</p>
  1. 這東西并不是一個(gè)指令城瞎,好像是引用什么的吧渤闷。官方的解釋是:ref 被用來(lái)給元素或子組件注冊(cè)引用信息。引用信息將會(huì)注冊(cè)在父組件的 $refs 對(duì)象上脖镀。如果在普通的 DOM 元素上使用飒箭,引用指向的就是 DOM 元素;如果用在子組件上蜒灰,引用就指向組件弦蹂。
  2. 其實(shí)可以把它看做id屬性,通過(guò)它獲取到該元素然后就可以進(jìn)行某些操作强窖。
  3. 如果想要輸出它里面的內(nèi)容凸椿,可以采用這種方式。注意這里的innerHTML只會(huì)輸出<p>標(biāo)簽中間部分的html內(nèi)容
console.log(this.$refs.fish.innerHTML);

自定義全局和局部指令

自定義全局指令

Vue.directive('upper-word', (el, binding)=>{
  console.log(el, binding);
  el.textContent = binding.value.toUpperCase();
});
  1. 全局指令需要寫(xiě)在main.js中
  2. Vue的指令都需要在前面加一個(gè)v-

自定義局部指令

directives: {
    'lower-word'(el, binding){
        console.log(el, binding);
        el.textContent = binding.value.toLowerCase();
    }
}
  1. 局部指令的定義使用的是directives這個(gè)鉤子選項(xiàng)
  2. 注意它和全局指令的定義有一些細(xì)微的不同翅溺。

計(jì)算屬性

  1. 計(jì)算屬性和data中的數(shù)據(jù)一樣脑漫,都可以使用v-model來(lái)進(jìn)行綁定
  2. 計(jì)算屬性都有set()get()方法,get()用于對(duì)data中的數(shù)據(jù)進(jìn)行計(jì)算咙崎,set()用于將從它獲取到的數(shù)據(jù)賦給data中的數(shù)據(jù)
fullNameTwo: {
        get(){
           // console.log(`調(diào)用了fullNameTwo的getter方法`);
           return this.firstName + '·' + this.lastName;
        },
        set(value){
            // console.log(`調(diào)用了fullNameTwo的setter方法,值:${value}`);
            // 1.更新firstName和lastName
            let names = value.split('·');
            console.log(names);
            this.firstName = names[0];
            this.lastName = names[1];
        }
    }

數(shù)據(jù)監(jiān)聽(tīng)watch

// 配置watch
watch: {
    // 監(jiān)聽(tīng)firstName
    firstName(value){
        console.log(`watch監(jiān)視到firstName發(fā)生改變:${value}`);
        // 更新fullNameThree
        this.fullNameThree = value + '·' + this.lastName;
    },

    // 監(jiān)聽(tīng)lastName
    lastName(value){
        console.log(`watch監(jiān)視到lastName發(fā)生改變:${value}`);
        // 更新fullNameThree
        this.fullNameThree = this.firstName + '·' + value;
    }
}
  1. watch和data优幸、computed是同一級(jí)屬性,可以用來(lái)對(duì)data中的數(shù)據(jù)進(jìn)行監(jiān)聽(tīng)褪猛。
  2. watch里面每個(gè)函數(shù)的名字與data里的屬性相同劈伴,當(dāng)該屬性被改變,就會(huì)自動(dòng)調(diào)用該方法握爷。
  3. 該方法可以內(nèi)部同樣可以中data中的數(shù)據(jù)進(jìn)行運(yùn)算跛璧。

事件處理

事件對(duì)象

<button @click="clickBtn('撩課', $event)">點(diǎn)我</button>
  1. 可以在觸發(fā)事件的同時(shí)將參數(shù)和事件對(duì)象都傳遞過(guò)去,該事件對(duì)象里面有很多很多與時(shí)間相關(guān)的屬性

事件修飾符@click.prevent

<a  @click.prevent="aClick">撩課</a>
  1. 它的存在是可以阻止該元素默認(rèn)的行為的新啼。
  2. 比如上面這個(gè)是個(gè)超鏈接追城,但是現(xiàn)在點(diǎn)擊之后并不會(huì)跳轉(zhuǎn),而是執(zhí)行aClick()方法
  3. 如果是form燥撞,也會(huì)阻止掉自動(dòng)提交的方法座柱。

事件修飾符@click.stop

<div style="width: 100px; height: 100px; background-color:red;" @click="divClick">
    <button @click.stop="btnClick">點(diǎn)我</button>
</div>
  1. 該修飾符是用在子元素標(biāo)簽上的迷帜,可以用來(lái)阻止事件冒泡。也就是說(shuō)色洞,使用之后戏锹,點(diǎn)擊子元素的標(biāo)簽并不會(huì)觸發(fā)父元素上的事件。

按鍵修飾符

<input type="text" @keyup.enter="dealKey">
dealKey(event){
    console.log(event);
    console.log(event['keyCode']);
}
  1. 使用@keyup可以在后面跟上很多種按鍵火诸,也就是當(dāng)按下然后松開(kāi)之后就會(huì)執(zhí)行該事件锦针。
  2. 另外在觸發(fā)事件的對(duì)象里可以通過(guò)event['keyCode']獲取按鍵的ASCII碼

過(guò)濾器

全局過(guò)濾器

Vue.filter('wholeMoneyFormat', (value)=>{
   return '¥' + Number(value).toFixed(4);
});
<p>{{money | wholeMoneyFormat}}</p>
  1. 全局過(guò)濾器需要寫(xiě)在main.js中,如上面的代碼所示
  2. 上面的過(guò)濾器的意思是:將傳過(guò)來(lái)的參數(shù)轉(zhuǎn)成數(shù)字置蜀,并且保留四位小數(shù)奈搜,然后在前面加上一個(gè)人民幣的符號(hào)并返回。
  3. 使用的時(shí)候需要使用雙括號(hào)表達(dá)式盯荤,第一個(gè)是需要過(guò)濾的參數(shù)馋吗,第二過(guò)濾器的名字,中間用豎線隔開(kāi)秋秤。

局部過(guò)濾器

filters: {
    moneyFormat(value){
        return '¥' + Number(value).toFixed(2);
    },
    timeFormat(value, format='YYYY-MM-DD HH:mm:ss'){
        return moment(value).format(format);
    }
}
  1. 局部過(guò)濾器的定義如上面的代碼所示宏粤。使用方法和全局過(guò)濾器是完全一樣的
  2. 第一個(gè)金錢過(guò)濾器,是將傳遞過(guò)來(lái)的參數(shù)轉(zhuǎn)成保留兩位小數(shù)的數(shù)字灼卢,并且在前面加上一個(gè)人民幣符號(hào)商架。
  3. 第二個(gè)時(shí)間過(guò)濾器需要使用moment插件,將value中的事件轉(zhuǎn)成format中的時(shí)間格式芥玉。當(dāng)然也可以在調(diào)用的時(shí)候手動(dòng)修改過(guò)濾的時(shí)間格式蛇摸。
<p>{{time | timeFormat('YYYY-MM-DD')}}</p>

Vue過(guò)渡和動(dòng)畫(huà)

只使用類

<button @click="show = !show">切換</button>
<transition name="fade">
    <div class="box" v-if="show">撩課學(xué)院</div>
</transition>
  1. 在Vue中使用動(dòng)畫(huà),需要使用transition標(biāo)簽灿巧,該標(biāo)簽必須具備一個(gè)name屬性
  2. 我們可以通過(guò)設(shè)置一個(gè)v-if來(lái)切換該元素出現(xiàn)和消失時(shí)的動(dòng)畫(huà)
  3. 然后在樣式表中寫(xiě)好終點(diǎn)的樣式以及進(jìn)行中的樣式赶袄。選擇器的名字需要使用到上面提到的name屬性,比如:.fade-enter, .fade-leave-to抠藕,.fade-enter-active, .fade-leave-active
  4. 下面這個(gè)就是一個(gè)CSS的例子
.fade-enter, .fade-leave-to{
    opacity: 0;
    transform: translateX(200px) scale(3);
}

.fade-enter-active, .fade-leave-active{
    transition: all 2s ease-in-out;
}

使用@keyframes

  1. 注意:如果圖片采用:src這種方式導(dǎo)入的話饿肺,需要先導(dǎo)入這樣圖片import pic from '@/assets/img_02.jpg',然后將其作為data中的一個(gè)數(shù)據(jù)
  2. 兩個(gè)CSS類盾似,第一個(gè)表示進(jìn)入時(shí)候的動(dòng)畫(huà)以及持續(xù)時(shí)間敬辣。第二個(gè)表示消失時(shí)候的動(dòng)畫(huà)以及持續(xù)時(shí)間,并且表明和第一個(gè)動(dòng)畫(huà)是相反的零院。
  3. 詳細(xì)代碼如下
<button @click="flag = !flag">切換</button>
<p></p>
<transition name="bounce">
    <img v-if="flag" :src="pic" alt="">
</transition>
.bounce-enter-active {
     animation: bounce 1s;
}

.bounce-leave-active {
    animation: bounce 1s reverse;
}

@keyframes bounce {
    0% {
        transform: scale(0);
    }
    25% {
        transform: scale(0.2);
    }
    50% {
        transform: scale(0.4);
    }
    75% {
        transform: scale(0.6);
    }
    100% {
        transform: scale(1);
    }
}

導(dǎo)入外部的動(dòng)畫(huà)CSS庫(kù)

<button @click="flag = !flag">切換</button>
<p></p>
<transition
    enter-active-class="animated rollIn"
    leave-active-class="animated rollOut"
    :duration="{ enter: 1000, leave: 500 }"
>
    <img v-if="flag" :src="pic" alt="">
</transition>
  1. 該動(dòng)畫(huà)庫(kù)的使用情況如上面的代碼
  2. 安裝animate.css:npm i animate.css --save
  3. 然后導(dǎo)入animate.cssimport animate from 'animate.css'
  4. transition中的三個(gè)屬性分別表示進(jìn)入時(shí)候的動(dòng)畫(huà)溉跃、消失時(shí)候的動(dòng)畫(huà),以及進(jìn)入和消失的持續(xù)時(shí)間告抄。

生命周期

  1. Vue的生命周期按順序有:beforeCreate撰茎、createdbeforeMount打洼、mounted龄糊、beforeUpdate逆粹、updated炫惩、beforeDestroydestroyed
  2. 一般來(lái)說(shuō)只要該組件啟用他嚷,前面四個(gè)生命周期都會(huì)很快依次調(diào)用蹋绽。
  3. 然后蟋字,每次修改data中的數(shù)據(jù)稿蹲,都會(huì)調(diào)用beforeUpdateupdated兩個(gè)方法
  4. 最后苛聘,如果想要進(jìn)入銷毀的生命周期需要主動(dòng)觸發(fā)下面代碼的這個(gè)方法
  5. 另外涂炎,定時(shí)器如果在生命周期里设哗,注意它是異步的,即便已經(jīng)銷毀可能定時(shí)器仍然在工作网梢。這個(gè)時(shí)候最好在銷毀的生命周期里設(shè)置一個(gè)清除定時(shí)器的方法。
destory(){
    this.$destroy();
}

組件通信

子組件通知父組件战虏,我觸發(fā)了某個(gè)方法

父組件

  1. App.vue在組件上面需要綁定事件
  2. 在methods中寫(xiě)事件
<CustomEvents @btnClick="deleteP"/>
deleteP(args){
    console.log(args);
    this.$refs.word.remove();
}

子組件

  1. 子組件同樣需要給某個(gè)元素綁定事件
  2. 但不是自己處理事件拣宰,而是告訴父元素,自己觸發(fā)了哪個(gè)事件烦感,參數(shù)是什么
btnClick(){
    // 告訴父組件巡社,我點(diǎn)擊了按鈕
    this.$emit('btnClick', {name: '哈哈哈', sex:'男'});
    // TODO
}

父組件向子組件傳遞數(shù)據(jù)和方法:props

<PropsComponent :age=25 :person="p" :log-person="logPerson" />
props: {
    name: String,
    age: Number,
    person: Object,
    logPerson: Function
}
*/
props: {
    name: {type: String, required: true, default: '撩課'},
    age:  {type: Number, required: true, default: 20},
    person: Object,
    logPerson: Function
}
  1. 父組件通過(guò)在組件上寫(xiě):age的形式,向子組件傳遞數(shù)據(jù)和方法手趣。這些數(shù)據(jù)和方法都是在父組件中已經(jīng)定義好的
  2. 子組件需要通過(guò)props這個(gè)鉤子選項(xiàng)接收父組件傳遞過(guò)來(lái)的數(shù)據(jù)和方法晌该,有上面兩種形式
  3. 然后子組件就可以像使用自己的數(shù)據(jù)和方法一樣使用父組件的數(shù)據(jù)和方法

自定義事件

  1. 由子組件發(fā)送給父組件,函數(shù)名稱绿渣,函數(shù)參數(shù)this.$emit('addTodo', todo);
  2. 父組件需要監(jiān)聽(tīng)這個(gè)組件:<Header ref="header"/>
  3. 然后給父組件綁定自定義事件的監(jiān)聽(tīng):this.$refs.header.$on('addTodo', this.addTodo);注意這是寫(xiě)在mounted這個(gè)鉤子選項(xiàng)里的朝群;然后不用寫(xiě)()來(lái)接參數(shù),這種寫(xiě)法就會(huì)自動(dòng)把todo參數(shù)傳遞過(guò)來(lái)

發(fā)布訂閱模式

  1. 安裝pubsub插件:npm install --save pubsub-js
  2. 在App.vue和item中引入pubsub-js:import PubSub from 'pubsub-js'中符,反正哪里需要發(fā)布潜圃、訂閱就需要引入
  3. 子組件發(fā)布消息:PubSub.publish('delTodo', this.index)
  4. 父組件接收消息。代碼如下舟茶。注意谭期,同樣寫(xiě)在mounted這個(gè)鉤子選項(xiàng)下堵第,token就是子組件傳遞過(guò)來(lái)的參數(shù)
PubSub.subscribe('delTodo', (msg, token)=>{
   // console.log(msg, token);
   this.delTodo(token);
});

插槽

<label>
    <slot name="isCheck"></slot>
</label>
<span>
    <slot name="finish"></slot>
</span>
<slot name="delete"></slot>
<Footer>
    <input slot="isCheck" type="checkbox" v-model="isCheck"/>
    <span slot="finish">已完成{{finishedCount}}件 / 總計(jì){{todos.length}}件</span>
    <button  slot="delete" class="btn btn-warning" @click="delFinishedTodos">清除已完成任務(wù)</button>
</Footer>
  1. footer中不用自己寫(xiě)代碼了,直接把插槽留出來(lái)就行隧出。使用的是<slot>標(biāo)簽踏志,注意必須有name屬性。
  2. 父組件里面直接往子組件里面插入
  3. 這樣就可以直接調(diào)用父組件里面的方法和計(jì)算屬性了

Vuex

  1. 安裝:vue add vuex

Vue router

Vue-router的基本使用

  1. 安裝:npm install vue-router --save
  2. 新建router.js文件
  3. 在main.js中引入胀瞪,并且放入Vue的實(shí)例中
  4. 新建view頁(yè)面针余,并且在App.vue中配置路由導(dǎo)航和路由出口

router.js

import Vue from 'vue'
import Router from 'vue-router'

// 引入頁(yè)面
import Home from './views/Home'
import About from './views/About'

Vue.use(Router);

export default new Router({
    // history模式就是沒(méi)有#
    // mode: 'history',
    routes: [
        { path: '/', redirect: '/home' },
        // 下面這個(gè)就是重定向到一個(gè)命名路由,name就是路由的名字
        // { path: '/', redirect: {name: 'about'} },
        // 下面這個(gè)是使用一個(gè)方法重定向到目標(biāo)路由
        // { path: '/', redirect: to => { return '/home'}},
        // 這里name屬性僅僅只是這個(gè)路由的名字凄诞,暫時(shí)沒(méi)有用處
        {path: '/home', name: 'home', component: Home},
        {path: '/about', name: 'about', component: About},
    ]
})

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false;

new Vue({
  router,
  render: h => h(App),
}).$mount('#app');

在App.vue中配置路由導(dǎo)航和路由出口

<!--設(shè)置路由導(dǎo)航-->
 <div id="nav">
     <router-link to="/home">首頁(yè)</router-link>
     <router-link to="/about">關(guān)于</router-link>
 </div>
 <!--設(shè)置路由出口-->
 <router-view></router-view>

路由history和hash模式

獲取路由參數(shù)

import Vue from 'vue'
import Router from 'vue-router'

// 引入頁(yè)面
import Home from './views/Home'
import About from './views/About'
import Mine from './views/Mine'

Vue.use(Router);

/*
let func = ({params, query})=>{
    return {
        name: params.name,
        sex: params.sex,
        height: query.height,
        dog: query.dog,
    }
};
*/

let func = (route)=>{
    return {
        name: route.params.name,
        sex: route.params.sex,
        height: route.query.height,
        dog: route.query.dog,
    }
};

export default new Router({
    routes: [
        { path: '/', redirect: '/home' },
        {path: '/home', name: 'home', component: Home},
        {path: '/about', name: 'about', component: About},
        // {path: '/mine/:name/:sex', name: 'mine', component: Mine}
        // {path: '/mine', name: 'mine', component: Mine, props: {name: '小撩'}}
        // {path: '/mine/:name/:sex', name: 'mine', component: Mine, props: true}
        {path: '/mine/:name/:sex', name: 'mine', component: Mine, props: func}
    ]
})

Mine.vue

<template>
    <div id="mine">
        <h2>個(gè)人中心</h2>

        <p>------------------------------------------</p>

        <h2>根據(jù)路由對(duì)象獲取的路徑參數(shù)</h2>
        <p>姓名:{{$route.params.name}}</p>
        <p>性別:{{$route.params.sex}}</p>
        <p>身高:{{$route.query.height}}</p>
        <p>小狗:{{$route.query.dog}}</p>

        <h2>根據(jù)屬性對(duì)象獲取的路徑參數(shù)</h2>
        <p>姓名:{{name}}</p>
        <p>性別:{{sex}}</p>
        <p>身高:{{height}}</p>
        <p>小狗:{{dog}}</p>
    </div>
</template>

<script>
    export default {
        name: "Mine",
        props: ['name', 'sex', 'height', 'dog'],
        created() {
            console.log(this.$route);
           /*
            console.log(this.$route);
            console.log(this.$route.path);
            console.log(this.$route.params);
            console.log(this.$route.query);
            */
            // console.log(this.$router);
        }
    }
</script>

<style scoped>
    #mine{
        width: 300px;
        height: 500px;
        background-color: orange;
        margin: 0 auto;
    }
    h2{
        color: green;
    }
</style>
  1. 關(guān)于獲取路由參數(shù)的代碼在上邊
  2. 所謂的獲取路由參數(shù)其實(shí)就是指圆雁,數(shù)據(jù)是在鏈接上的,我們需要通過(guò)某種方式獲取到這些數(shù)據(jù)
  3. 通過(guò)路由傳遞參數(shù)主要有幾種方式:
  4. {path: '/mine/:name/:sex', name: 'mine', component: Mine}帆谍,通過(guò)在路由上寫(xiě)冒號(hào)
  5. {path: '/mine', name: 'mine', component: Mine, props: {name: '小撩'}}伪朽,通過(guò)props獲取數(shù)據(jù),注意需要在該組件內(nèi)部寫(xiě)出props這個(gè)鉤子選項(xiàng)汛蝙,并且內(nèi)容為這些數(shù)據(jù)的變量名
  6. {path: '/mine/:name/:sex', name: 'mine', component: Mine, props: true}烈涮,通過(guò)以上兩種方式獲取數(shù)據(jù)
  7. {path: '/mine/:name/:sex', name: 'mine', component: Mine, props: func},通過(guò)地址和方法傳遞數(shù)據(jù)

嵌套路由

import Vue from 'vue'
import Router from 'vue-router'

// 一級(jí)界面
import Home from './views/Home'
import About from './views/About'
import Mine from './views/Mine'

// 二級(jí)界面
import News from './views/News'
import Shop from './views/Shop'

Vue.use(Router);

export default new Router({
    routes: [
        { path: '/', redirect: '/home' },
        {
            path: '/home',
            name: 'home',
            component: Home,
            children: [
                { path: '/home', redirect: '/home/news' },
                {path: 'news', name: 'news', component: News},
                {path: 'shop', name: 'shop', component: Shop},
            ]
        },
        {path: '/about', name: 'about', component: About},
        {path: '/mine', name: 'mine', component: Mine}
    ]
})
  1. 所謂的嵌套路由就是斜杠后面還有斜杠
  2. 嵌套路由的配置其它文件并沒(méi)有什么不同窖剑,主要還是在router.js上的不同
  3. 嵌套路由的配置主要小心:子路由不需要在前面寫(xiě)/

全局路由前置和后置守衛(wèi)

import Vue from 'vue'
import Router from 'vue-router'

// 一級(jí)界面
import Login from './views/Login'
import DashBoard from './views/DashBoard'

// 二級(jí)界面
import Home from './views/Home'
// import About from './views/About'
import Mine from './views/Mine'

const About = ()=> import('./views/About');


Vue.use(Router);

const router = new Router({
    routes: [
        { path: '/', redirect: '/dashboard' },
        {
            path: '/dashboard',
            name: 'dashboard',
            component: DashBoard,
            children: [
                { path: '/dashboard', redirect: '/dashboard/home' },
                {path: 'home', name: 'home', component: Home,},
                {path: 'about', name: 'about', component: About},
                {path: 'mine', name: 'mine', component: Mine}
            ],
        },
        {path: '/login', name: 'login', component: Login}
    ]
});

// 全局路由前置守衛(wèi)
router.beforeEach((to, from, next)=>{
    // console.log(to, from);
    if(to.path !== '/login'){ // 驗(yàn)證是否登錄
        if(window.isLogin){ // 已經(jīng)登錄
            next();
        }else { // 沒(méi)有登錄
            // 將你要去的地址也傳到登錄頁(yè)去坚洽,這樣當(dāng)你登錄成功之后可以立即重定向到該頁(yè)
            // next('/login?redirect='+ to.path);
            // next('/login?redirect=/dashboard/mine');
            next('/login');
        }
    }else { // 不需要驗(yàn)證
        next();
    }
    // 放行
    next();
});

// 全局路由后置守衛(wèi)
router.afterEach((to, from) => {
   // console.log('來(lái)了!');
});

export default router;
  1. 主要通過(guò)前置守衛(wèi)來(lái)控制什么情況下用戶可以進(jìn)入頁(yè)面
  2. 如果用戶進(jìn)的是登錄頁(yè)西土,無(wú)需檢查直接放行
  3. 如果用戶進(jìn)的是其它頁(yè)讶舰,檢查是否登錄,如果沒(méi)有登錄前往登錄頁(yè)需了,如果已經(jīng)登錄放行
  4. 其它情況一律放行

mine.vue

export default {
    name: "Mine",
    beforeRouteEnter(to, from, next){
        console.log('進(jìn)入之前調(diào)用');
        next();
    },
    beforeRouteUpdate(to, from, next){
        console.log('路由的參數(shù)變了');
        next();
    },
    beforeRouteLeave(to, from, next){
        console.log('路由離開(kāi)前調(diào)用');
        next();
    }
}

這里主要設(shè)置了幾個(gè)生命周期的鉤子選項(xiàng)跳昼,在進(jìn)入這個(gè)組件之前庐舟、路由參數(shù)改變、以及路由離開(kāi)的時(shí)候都會(huì)分別調(diào)用這里的方法

login.vue

<template>
    <div>
        <h2>登錄界面</h2>
        <button @click="login">登錄</button>
    </div>
</template>

<script>
    export default {
        name: "Login",
        methods: {
            login(){
                // 1. 登錄成功
                window.isLogin = true;
                // 2. 獲取回調(diào)地址
                const redirect = this.$route.query.redirect;
                if(redirect){ // 有回調(diào)地址
                    this.$router.push(redirect);
                }else { // 沒(méi)有回調(diào)地址
                    // 去首頁(yè)
                    this.$router.replace('/');
                }
            }
        }
    }
</script>

<style scoped>

</style>
  1. 登錄的這個(gè)頁(yè)面主要負(fù)責(zé)處理登錄相關(guān)的事務(wù)
  2. 當(dāng)用戶點(diǎn)擊登錄按鈕之后挪略,首先將全局的isLogin設(shè)置為true
  3. 獲取用戶的回調(diào)地址杠娱,如果有回調(diào)地址則直接前往谱煤;如果沒(méi)有則前往主頁(yè)

數(shù)據(jù)本地化

  1. 手寫(xiě)一個(gè)工具類
  2. 在app.vue中導(dǎo)入該工具類
  3. data中的數(shù)據(jù)需要從localStorage中讀取,當(dāng)todos數(shù)據(jù)發(fā)生任何改變就要把該數(shù)據(jù)存儲(chǔ)到localStorage

工具類

const LK_TODO = 'lk_todo';
export default {
    readTodos(){
        return JSON.parse(localStorage.getItem(LK_TODO) || '[]');
    },
    saveTodos(todos){
        console.log(todos);
        localStorage.setItem(LK_TODO, JSON.stringify(todos));
    }
}
  1. 使用localStorage無(wú)論是讀還是取室叉,都需要傳遞一個(gè)key,注意這里僅僅一個(gè)數(shù)組茧痕,所以使用了一個(gè)字符串常量作為key
  2. 第一個(gè)讀取數(shù)據(jù)的方法內(nèi)部有|| '[]'是為了在任何情況下都能夠讀到數(shù)據(jù),哪怕是一個(gè)空的數(shù)組

讀數(shù)據(jù)

todos: localStorageUtil.readTodos()

取數(shù)據(jù)

watch: {
    // 深度監(jiān)視
    todos: {
        handler: localStorageUtil.saveTodos,
        deep: true, // 深度監(jiān)視
        // immediate: true
    }
}
  1. 取數(shù)據(jù)需要深度監(jiān)視曼氛,因?yàn)閿?shù)組里面還有對(duì)象令野,只有深度監(jiān)視能夠監(jiān)聽(tīng)數(shù)組里面對(duì)象屬性的改變。
  2. immediate如果為true气破,就是當(dāng)初始化的時(shí)候就立即執(zhí)行handler方法,否則就是當(dāng)todos發(fā)生改變才會(huì)執(zhí)行handler方法狗超。

UI框架

elementUI

  1. element文檔:https://element.eleme.cn/#/zh-CN/component/layout
  2. 安裝:npm i element-ui -S
  3. 給Vue添加UI庫(kù):vue add element
  4. 選項(xiàng):Fully import朴下、N苦蒿、CN
  5. vue ui:使用可視化面板管理項(xiàng)目(一般不會(huì)用的)

做完以上幾步就會(huì)發(fā)現(xiàn),自動(dòng)集成了plugins/element.js团滥,并且自動(dòng)在main.js中導(dǎo)入了报强。然后就可以直接在app.vue中使用了。

  1. 復(fù)制HTML代碼到模板里面
  2. 復(fù)制script代碼data部分到app.vue里力惯,注意這里和vue的代碼結(jié)構(gòu)是完全一樣的召嘶。

VantUI

  1. 文檔:https://youzan.github.io/vant/#/zh-CN/
  2. 安裝:npm i vant -S
  3. 配置按需加載,引入babel:npm i babel-plugin-import -D
  4. 配置babel.config.js甲喝,可以從文檔里復(fù)制粘貼
  5. 在main.js從引入需要的組件铛只,或者單獨(dú)做一個(gè)js文件糠溜,然后通過(guò)import來(lái)引入

配置babel.config.js

module.exports = {
  presets: [
    '@vue/app'
  ],
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
};

在main.js中引入需要的組件

import { Button } from 'vant';
Vue.use(Button);
import { Cell, CellGroup } from 'vant';
Vue.use(Cell).use(CellGroup);
import { DatetimePicker } from 'vant';
Vue.use(DatetimePicker);

插件的安裝和使用

shortid

<ul>
    <li v-for="(person, index) in persons" :key="personsKeys[index]">
        ID: {{personsKeys[index]}} ---- {{index}} ) 姓名:{{person.name}}, 年齡:{{person.age}}, 性別:{{person.sex}}
    </li>
</ul>
  1. 安裝shortidnpm i shortid --save
  2. 在該組件中導(dǎo)入:import shortId from 'shortid'
  3. 在data中要有personsKeys這個(gè)數(shù)據(jù)诵冒,它是一個(gè)空的數(shù)組
  4. 注意要添加一個(gè)mounted掛載點(diǎn)谊惭,調(diào)用shortid自動(dòng)產(chǎn)生一個(gè)隨機(jī)數(shù)作為id
mounted() {
    this.personsKeys = this.persons.map(v=>shortId.generate())
}
  1. 然后就可以如上面代碼部分那樣使用了
  2. v-for可能需要使用:key這個(gè)屬性,不然的話可能在控制臺(tái)會(huì)報(bào)警告

moment

  1. 安裝:npm i moment --save
  2. 使用:注意任何插件的使用圈盔,都需要在該組件內(nèi)部首先導(dǎo)入import moment from 'moment'。然后就可以像調(diào)用函數(shù)一樣使用該插件了

案例匯總

v-for排序小案例

  1. 數(shù)據(jù)來(lái)源于data中已經(jīng)定義好的
  2. v-for的使用和之前遍歷數(shù)組的時(shí)候是一樣的铁蹈,同樣用到了shortid众眨,但是并沒(méi)有把shortid展示在頁(yè)面上,而是用索引加1的方式
  3. v-for里的in沿腰,是已經(jīng)排序好的數(shù)組狈定,該數(shù)組是使用計(jì)算屬性而得到的
  4. 排序分為默認(rèn),按年齡升序措嵌、降序芦缰,是通過(guò)向計(jì)算屬性里傳遞不同參數(shù)而區(qū)別開(kāi)的。
  5. 排序的代碼如下浪规。注意需要先過(guò)濾以下數(shù)組,然后根據(jù)條件進(jìn)行排序
computed: {
    filterPersons() {
        // 1. 獲取數(shù)據(jù)
        let {searchName, persons, orderType} = this;
        // 2. 取出數(shù)組中的數(shù)據(jù)
        let arr = [...persons];
        // 3. 過(guò)濾數(shù)組
        if (searchName.trim()) {
            arr = persons.filter(p => p.name.indexOf(searchName) !== -1);
        }
        // 4. 排序
        if (orderType) {
            arr.sort((p1, p2) => {
                if (orderType === 1) { // 降序
                    return p2.age - p1.age
                } else { // 升序
                    return p1.age - p2.age
                }
            });
        }
        return arr;
    }
},

表單添加刪除小案例

  1. data里有有已經(jīng)存在的數(shù)據(jù)和一個(gè)新的空對(duì)象對(duì)象罗丰,這個(gè)空對(duì)象可以設(shè)定一些默認(rèn)值
  2. 每個(gè)input標(biāo)簽都會(huì)設(shè)置v-model萌抵,分別和空對(duì)象里的各個(gè)屬性綁定起來(lái)
  3. 添加數(shù)據(jù)的時(shí)候:首先使用解構(gòu)賦值從該對(duì)象中獲取輸入框的數(shù)據(jù);然后對(duì)數(shù)據(jù)進(jìn)行驗(yàn)證霎桅,比如不能為空讨永;插入數(shù)據(jù)直接使用數(shù)組的unshift方法就可以;最后記得要清空這個(gè)空對(duì)象卿闹,讓其恢復(fù)默認(rèn)值
  4. 點(diǎn)擊刪除按鈕的時(shí)候:直接調(diào)用splice方法就可以,第一個(gè)參數(shù)是索引著角,第二個(gè)參數(shù)是從該索引的位置刪除幾個(gè)元素

todoList

todoList第一版

Header
  1. Header的主要任務(wù)是為todoList添加新任務(wù)旋恼,主要方法就是添加todo
  2. 方法的實(shí)現(xiàn)是在App.vue,然后使用:addTodo="addTodo"的方式向子組件傳遞自己的方法产徊。當(dāng)然子組件需要用props來(lái)接收蜀细。
  3. 子組件只負(fù)責(zé)一個(gè)數(shù)據(jù)title,因?yàn)閯?chuàng)建的時(shí)候任務(wù)不可能完成深滚,所以finished也就是那個(gè)復(fù)選框默認(rèn)設(shè)置為false就行了涣觉。
  4. 子組件仍需要一些其它的操作:①:判斷用戶輸入的是否是空字符串;②:根據(jù)用戶的輸入拼接一個(gè)todo官册,它主要就是包含title难捌、finished兩個(gè)數(shù)據(jù);③:調(diào)用父組件的添加方法员淫;④:清空title數(shù)據(jù)
List
  1. List的主要任務(wù)就是:①:當(dāng)鼠標(biāo)移動(dòng)到某一條todo上時(shí)击敌,該todo的背景顏色變?yōu)榛疑⑶绎@示出來(lái)刪除按鈕
  2. App.vue需要向List傳遞todos數(shù)據(jù)和刪除某一條todo的方法
  3. List使用props接收todos和刪除方法圣蝎。然后使用v-for對(duì)todos進(jìn)行遍歷,當(dāng)然遍歷的每一個(gè)item就是它的子組件徘公,List需要向item傳遞它的數(shù)據(jù)todo、該todo在todos中的索引坦袍,以及刪除todo的方法
  4. 子子組件item首先需要接收上面?zhèn)鬟f過(guò)來(lái)的兩個(gè)數(shù)據(jù)一個(gè)方法等太。
  5. item實(shí)現(xiàn)鼠標(biāo)移入就出現(xiàn)刪除按鈕以及背景顏色的改變是通過(guò)@mouseenter@mouseleave兩個(gè)觸發(fā)事件的方式澈驼,分別向同一個(gè)事件傳遞truefalse兩個(gè)不同的參數(shù)挎塌。
  6. 背景顏色是通過(guò)設(shè)置:style使用的是data里面的某個(gè)值内边,這樣就可以使用方法改變data的這個(gè)屬性來(lái)調(diào)整背景顏色
  7. 按鈕的顯示和隱藏使用的是v-show,同樣是data里的一個(gè)數(shù)據(jù)控制true還是false嘴高,這樣我們?cè)诜椒ɡ锞涂梢栽O(shè)置該屬性為true,來(lái)讓按鈕顯示出來(lái)
  8. 刪除該todo直接使用父組件里的方法就可以了
Footer
  1. footer的作用主要是:①:當(dāng)上面的每一條todo都選中的時(shí)候拴驮,它的復(fù)選框也要選中柴信;②:全選;③:點(diǎn)擊刪除所有finished的按鈕潜沦。
  2. 選中所有todo和刪除已經(jīng)完成的todo都是在app.vue中定義的。然后將這兩個(gè)方法以及todos的數(shù)據(jù)全部傳遞給footer組件
  3. footer里面很重要的一個(gè)功能就是要知道目前已經(jīng)完成的todo數(shù)量唆鸡,這是通過(guò)計(jì)算屬性實(shí)現(xiàn)的枣察。代碼見(jiàn)下方袄琳。使用的是數(shù)組的reduce這個(gè)方法燃乍,其實(shí)就是一個(gè)遍歷+1計(jì)數(shù)的操作。
  4. footer里面很重要的一個(gè)功能就是全選逗旁,也就是當(dāng)上面全部選中它也要選中,它如果選中片效,上面也要全部選中英古。這是通過(guò)給該復(fù)選框設(shè)置一個(gè)v-model,并且綁定一個(gè)計(jì)算屬性實(shí)現(xiàn)的膨桥。
  5. 其中g(shù)et()是處理第一個(gè)的唠叛,判斷條件就是目前已經(jīng)完成的todo數(shù)量和todos的長(zhǎng)度相等,并且長(zhǎng)度不為0.
  6. 其中set()是處理第二個(gè)的艺沼,它會(huì)將目前該計(jì)算屬性的值true、false作為參數(shù)調(diào)用父組件的全選方法调鲸。父組件的全選方法就會(huì)遍歷整個(gè)todos挽荡,將其中的finished屬性全部設(shè)定為參數(shù)。需要注意的是贯钩,這里有一個(gè)小竅門(mén),就是footer的全選按鈕和v-model綁定,它選中那么set()方法的參數(shù)就是true祸穷。
  7. 最后刪除所有已經(jīng)完成的todo則很簡(jiǎn)單了,不需要傳遞任何參數(shù)需曾,直接調(diào)用父組件的方法即可。
finishedCount(){
    return this.todos.reduce((total, todo)=> total + (todo.finished ? 1 : 0), 0);
},
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末商源,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子牡彻,更是在濱河造成了極大的恐慌出爹,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件总寻,死亡現(xiàn)場(chǎng)離奇詭異渐行,居然都是意外死亡铸董,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)袒炉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人孽文,你說(shuō)我怎么就攤上這事夺艰。” “怎么了郁副?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵存谎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我既荚,道長(zhǎng),這世上最難降的妖魔是什么恰聘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任吸占,我火速辦了婚禮矾屯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘件蚕。我一直安慰自己惧所,他們只是感情好下愈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著势似,像睡著了一般侄旬。 火紅的嫁衣襯著肌膚如雪脖咐。 梳的紋絲不亂的頭發(fā)上私杜,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音毅舆,去河邊找鬼。 笑死岂津,一個(gè)胖子當(dāng)著我的面吹牛吮成,可吹牛的內(nèi)容都是我干的辜梳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼冗美,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了节预?” 一聲冷哼從身側(cè)響起属韧,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宵喂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后锅棕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體裸燎,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年荷荤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了移稳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡古毛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出稻薇,到底是詐尸還是另有隱情梭稚,我是刑警寧澤弧烤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站莺戒,受9級(jí)特大地震影響急波,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜名段,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望麻惶。 院中可真熱鬧信夫,春花似錦、人聲如沸静稻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至恰梢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嵌言,已是汗流浹背嗅回。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摧茴,地道東北人绵载。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像苛白,于是被迫代替她去往敵國(guó)和親娃豹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354