加快 Vue 項目的開發(fā)速度

現(xiàn)如今的開發(fā),比如內(nèi)部使用的管理平臺這種項目大都時間比較倉促。實際上來說,在使用了webpack + vue 這一套來開發(fā)的話已經(jīng)大大了提高了效率。但是對于我們的開發(fā)層面。還是有很多地方可以再次提高我們的項目開發(fā)效率,讓我們更加專注于業(yè)務,畢竟時間就是生命。下面我們挨個來探討。

巧用Webpack

Webpack是實現(xiàn)我們前端項目工程化的基礎,但其實她的用處遠不僅僅如此,我們可以通過Webpack來幫我們做一些自動化的事情。首先我們要了解require.context()這個API

require.context()

您可以使用require.context()函數(shù)創(chuàng)建自己的上下文。 它允許您傳入一個目錄進行搜索,一個標志指示是否應該搜索子目錄,還有一個正則表達式來匹配文件。

其實是Webpack通過解析 require() 的調(diào)用,提取出來如下這些信息:

Directory:?./template

Regular expression:?/^.*.ejs$/

然后來創(chuàng)建我們自己的上下文,什么意思呢,就是我們可以通過這個方法篩選出來我們需要的文件并且讀取

下面我們來簡單看一看使用:

/**

* @param directory 要搜索的文件夾目錄不能是變量,否則在編譯階段無法定位目錄

* @param useSubdirectories 是否搜索子目錄

* @param regExp 匹配文件的正則表達式

* @return function 返回一個具有 resolve, keys, id 三個屬性的方法

??????????resolve() 它返回請求被解析后得到的模塊 id

??????????keys() 它返回一個數(shù)組,由所有符合上下文模塊處理的請求組成。

??????????id 是上下文模塊里面所包含的模塊 id. 它可能在你使用 module.hot.accept 的時候被用到

*/

require.context('demo',?useSubdirectories?=?false,?regExp?=?/.js$/)

// (創(chuàng)建了)一個包含了 demo 文件夾(不包含子目錄)下面的、所有文件名以 `js` 結尾的、能被 require 請求到的文件的上下文。

不要困惑,接下來我們來探討在項目中怎么用。

組織路由

對于Vue中的路由,大家都很熟悉,類似于聲明式的配置文件,其實已經(jīng)很簡潔了?,F(xiàn)在我們來讓他更簡潔。

1、分割路由

首先為了方便我們管理,我們把router目錄下的文件分割為以下結構:

router?// 路由文件夾

??|__index.js?// 路由組織器:用來初始化路由等等

??|__common.js?// 通用路由:聲明通用路由

??|__modules?// 業(yè)務邏輯模塊:所以的業(yè)務邏輯模塊

????????|__index.js?// 自動化處理文件:自動引入路由的核心文件

????????|__home.js?// 業(yè)務模塊home:業(yè)務模塊

????????|__a.js?// 業(yè)務模塊a

2、modules文件夾中處理業(yè)務模塊

modules文件夾中存放著我們所有的業(yè)務邏輯模塊,至于業(yè)務邏輯模塊怎么分,我相信大家自然有自己的一套標準。我們通過上面提到的require.context()接下來編寫自動化的核心部分index.js。

const?files?=?require.context('.',?true,?/.js$/)


console.log(files.keys())?// ["./home.js"] 返回一個數(shù)組

let?configRouters?=?[]

/**

* inject routers

*/

files.keys().forEach(key?=>?{

??if?(key?===?'./index.js')?return

??configRouters?=?configRouters.concat(files(key).default)?// 讀取出文件中的default模塊

})

export?default?configRouters?// 拋出一個Vue-router期待的結構的數(shù)組

自動化部分寫完了,那業(yè)務組件部分怎么寫? 這就更簡單了。

import?Frame?from?'@/views/frame/Frame'

import?Home?from?'@/views/index/index'

export?default?[

????// 首頁

????{

??????path:?'/index',

??????name:?'首頁',

??????redirect:?'/index',

??????component:?Frame,

??????children:?[?// 嵌套路由

????????{

??????????path:?'',

??????????component:?Home

????????}

??????]

????}

]

3、common路由處理 我們的項目中有一大堆的公共路由需要處理比如404,503等等路由我們都在common.js中進行處理。

export?default?[

??// 默認頁面

??{

????path:?'/',

????redirect:?'/index',

????hidden:true

??},

??// 無權限頁面

??{

????path:?'/nopermission',

????name:?'nopermission',

????component:?()?=>?import('@/views/NoPermission')

??},

??// 404

??{

????path:?'*',

????name:?'lost',

????component:?()?=>?import('@/views/404')

??}

]

4、路由初始化這是我們的最后一步了,用來初始化我們的項目路由。

import?Vue?from?'vue'

import?VueRouter?from?'vue-router'

import?RouterConfig?from?'./modules'?// 引入業(yè)務邏輯模塊

import?CommonRouters?from?'./common'?// 引入通用模塊

Vue.use(VueRouter)

export?default?new?VueRouter({

??mode:?'history',// 需要服務端支持

??scrollBehavior:?()?=>?({?y:?0?}),

??routes:?RouterConfig.concat(CommonRouters)

})

估計有些朋友代碼寫到這還不知道到底這樣做好處在哪里。我們來描述一個場景,比如按照這種結構來劃分模塊。正常的情況是我們創(chuàng)建完home.js要手動的把這個模塊import到路由文件聲明的地方去使用。但是有了上面的index.js,在使用的時候你只需要去創(chuàng)建一個home.js并拋出一個符合VueRouter規(guī)范的數(shù)組,剩下的就不用管了。import RouterConfig from './modules' // 引入業(yè)務邏輯模塊 已經(jīng)幫你處理完了。另外擴展的話你還可以把hooks拿出來作為一個單獨文件。

全局組件統(tǒng)一聲明

同樣的道理,有了上面的經(jīng)驗,我們照葫蘆畫瓢來處理一下我們的全局組件。這就沒什么可說的了,直接上核心代碼。

1、組織結構

components?// 組件文件夾

??|__xxx.vue?// 其他組件

??|__global?// 全局組件文件夾

????????|__index.js?// 自動化處理文件

????????|__demo.vue?// 全局demo組件

2、global處理

import?Vue?from?'vue'

let?contexts?=?require.context('.',?false,?/.vue$/)

contexts.keys().forEach(component?=>?{

??let?componentEntity?=?contexts(component).default

??// 使用內(nèi)置的組件名稱 進行全局組件注冊

??Vue.component(componentEntity.name,?componentEntity)

})

3、使用和說明

這個使用起來就更簡單了,直接在app.js引用這個文件就行。

注意:我之前看到有些人做法是使用組件名去區(qū)分全局組件和普通組件,然后通過正則去判斷需不需要全局注冊。我是直接把全局的組件放到global文件夾下,然后組件的注冊名稱直接使用component.name。至于使用哪種方式就比較看個人了。

充分利用NodeJS

放著node這么好的東西不用真是有點浪費,那么我們來看看node能為我們提高效率做出什么貢獻。

有這么一個場景,我們每次創(chuàng)建模塊的時候都要新建一個vue文件和對應的router配置,而且新頁面的大部分東西都還差不多,還得去復制粘貼別的頁面。這想想就有點low。那既然有node我們可不可以通過node來做這些亂七八糟的事情? 下面來把我們的想法付諸于現(xiàn)實。

我們實現(xiàn)這個功能主要要借助Node的fs和process, 感興趣的話可以深入研究一下。

首先我們要編寫我們的node腳本,這里是一個比較簡單的版本。什么驗證文件夾或者文件的都沒有,只是來實現(xiàn)我們這個想法:

/*

?* fast add new module script

?*/

const?path?=?require('path')

const?fs?=?require('fs')

const?chalk?=?require('chalk')

const?reslove?=?file?=>?path.resolve(__dirname,?'../src',?file)

// symbol const

const?RouterSymbol?=?Symbol('router'),

??????ViewsSymbol?=?Symbol('views')

// root path

const?rootPath?=?{

??[RouterSymbol]:?reslove('router/modules'),

??[ViewsSymbol]:?reslove('views')

}

//loggs

const?errorLog?=?error?=>?console.log(chalk.red(`${error}`))

const?defaultLog?=?log?=>?console.log(chalk.green(`${log}`))

// module name

let?moduleName?=?new?String()

let?fileType?=?new?String()

//const string

const?vueFile?=?module?=>?(`<template>


</template>


<script>

export default {

??name: '${module}',

??data () {

????return {


????}

??},

??methods: {


??},

??created() {


??}

}

</script>


<style lang="less">


</style>

`)

// route file

const?routerFile?=?module?=>?(`// write your comment here...

export default [

??{

????path: '/${module}',

????name: '',

????redirect: '/${module}',

????component: () => import('@/views/frame/Frame'),

????children: [

??????{

????????path: '',

????????fullPath: '',

????????name: '',

????????component: () => import('@/views/${module}/index')

??????}

????]

??}

]

`)

/**

?* generate file

?* @param {*} filePath

?* @param {*} content

?* @param {*} dirPath

?*/

const?generateFile?=?async?(filePath,?content,?dirPath?=?'')?=>{

??try?{

????// create file if file not exit

????if?(dirPath?!==?''?&&?!?await?fs.existsSync(dirPath))?{

??????await?fs.mkdirSync(dirPath)

??????defaultLog(`created?${dirPath}`)

????}

????if?(!?await?fs.existsSync(filePath))?{

??????// create file

??????await?fs.openSync(filePath,?'w')

??????defaultLog(`created?${filePath}`)

????}

????await?fs.writeFileSync(filePath,?content,?'utf8')

??}?catch?(error)?{

????errorLog(error)

??}

}

// module-method map

const?generates?=?new?Map([

??['view',?async?(module)?=>?{

????// module file

????const?filePath?=?path.join(rootPath[ViewsSymbol],?module)

????const?vuePath?=?path.join(filePath,?'/index.vue')

????await?generateFile(vuePath,?vueFile(module),?filePath)

??}],

??// router is not need new folder

??['router',async?(module)?=>?{

????const?routerPath?=?path.join(rootPath[RouterSymbol],?`/${module}.js`)

????await?generateFile(routerPath,?routerFile(module))

??}]

])

defaultLog(`請輸入模塊名稱(英文):`)

// files

const?files?=?['view',?'router']

// 和命令行進行交互 獲取的創(chuàng)建的模塊名稱

process.stdin.on('data',?(chunk)?=>?{

??try?{

????if?(!moduleName)?{

??????moduleName?=?chunk

????}?else?{

??????chunk?=?chunk.slice(0,-2)?// delete /n

??????defaultLog(`new module name is?${chunk}`)

??????files.forEach(async?(el,?index)?=>?{

????????// 執(zhí)行創(chuàng)建語句

????????await?generates.get(`${el}`).call(null,?chunk.toString())

????????if?(index?===?files.length-1)?{

??????????process.stdin.emit('end')

????????}

??????})

????}

??}?catch?(error)?{

????errorLog(error)

??}

})

process.stdin.on('end',?()?=>?{

??defaultLog('create module success')

})

下面我們看使用的流程

這樣我們就分別創(chuàng)建了vue和router的文件,而且已經(jīng)注入了內(nèi)容。按照我們提前聲明的組件

注意:這只是一個簡單的思路,通過Node強大的文件處理能力,我們能做的事情遠不止這些。

發(fā)揮Mixins的威力

Vue中的混入mixins是一種提供分發(fā) Vue 組件中可復用功能的非常靈活的方式。聽說在3.0版本中可能會用Hooks的形式實現(xiàn),但這并不妨礙它的強大。這里主要來討論mixins能在什么情景下幫助我們。

通用mixins

如果我們有大量的表格頁面,仔細一扒拉你發(fā)現(xiàn)非常多的東西都是可以復用的例如分頁,表格高度,加載方法, laoding聲明等一大堆的東西。下面我們來整理出來一個簡單通用混入list.js

const?list?=?{

??data?()?{

????return?{

??????// 這些東西我們在list中處理,就不需要在每個頁面再去手動的做這個了。

??????loading:?false,?// 伴隨loading狀態(tài)

??????pageNo:?1,?// 頁碼

??????pageSize:?15,?// 頁長

??????totalCount:?0,?// 總個數(shù)

??????pageSizes:?[15,?20,?25,?30],?//頁長數(shù)

??????pageLayout:?'total, sizes, prev, pager, next, jumper',?// 分頁布局

??????list:?[]

????}

??},

??methods:?{

????// 分頁回調(diào)事件

????handleSizeChange(val)?{

??????this.pageSize?=?val

??????// todo

????},

????handleCurrentChange?(val)?{

??????this.pageNo?=?val

??????// todo

????},

????/**

?????* 表格數(shù)據(jù)請求成功的回調(diào) 處理完公共的部分(分頁,loading取消)之后把控制權交給頁面

?????* @param {*} apiResult

?????* @returns {*} promise

?????*/

????listSuccessCb?(apiResult?=?{})?{

??????return?new?Promise((reslove,?reject)?=>?{

????????let?tempList?=?[]?// 臨時list

????????try?{

??????????this.loading?=?false

??????????// todo

??????????// 直接拋出

??????????reslove(tempList)

????????}?catch?(error)?{

??????????reject(error)

????????}

??????})

????},

????/**

?????* 處理異常情況

?????* ==> 簡單處理 僅僅是對表格處理為空以及取消loading

?????*/

????listExceptionCb?(error)?{

??????this.loading?=?false

??????console.error(error)

????}

??},

??created()?{

????// 這個生命周期是在使用組件的生命周期之前

????this.$nextTick().then(()?=>?{

??????// todo

????})

??}

}

export?default?list

下面我們直接在組件中使用這個mixins

import?mixin?from?'@/mixins/list'?// 引入

import?{getList}?from?'@/api/demo'

export?default?{

??name:?'mixins-demo',

??mixins:?[mixin],?// 使用mixins

??data?()?{

????return?{

????}

??},

??methods:?{

????// 加載列表

????load?()?{

??????const?para?=?{

??????}

??????this.loading?=?true

??????getList(para).then((result)?=>?{

????????this.listSuccessCb(result).then((list)?=>?{

??????????this.list?=?list

????????}).catch((err)?=>?{

??????????console.log(err)

????????})

??????}).catch((err)?=>?{

????????this.listExceptionCb(err)

??????})

????}

??},

??created()?{

????this.load()

??}

}

使用了mixins之后一個簡單的有l(wèi)oadoing, 分頁,數(shù)據(jù)的表格大概就只需要上面這些代碼。

mixins做公共數(shù)據(jù)的管理

有些時候我們有一些公共的數(shù)據(jù)它可能3,4個模塊取使用但是又達不到全局的這種規(guī)模。這個時候我們就可以用mixins去管理他們,比如我們有幾個模塊要使用用戶類型這個列表,我們來看使用mixins來實現(xiàn)共享。

// types.js

import?{getTypes}?from?'@/api/demo'?// ajax

export?default?{

??data?()?{

????return?{

??????types:?[]?// ==> {name: '', value: ''}

????}

??},

??methods:?{

????// 獲取列表

????getAllTypesList?()?{

??????getApiList().then((result)?=>?{

????????// todo

????????this.types?=?result?// 假設result就是我們需要使用的數(shù)據(jù)

??????}).catch((err)?=>?{

????????console.error(err)

??????})

????}

??},

??created()?{

????// 在需要使用這個mixins的時候取自動請求數(shù)據(jù) 這個可要可不要 你想在父組件中執(zhí)行也是ok的

????this.getAllTypesList()

??}

}

在組件中引用

import?typeMixin?from?'@/mixins/types'

export?default?{

??name:?'template',

??mixins:?[typeMixin],

??data?()?{

????return?{

??????// types這個數(shù)組在使用組件中不用多余的定義,直接拿來用就行

??????type:?''

????}

??},

??methods:?{

??}

}

至于mixins中得數(shù)據(jù)我們可以在組件中直接使用

<!--?-->

<el-select v-model="type"?clearable placeholder="請選擇類型">

????<el-option v-for="item in types"?:key="item.id"?:label="item.templateName"?:value="item.id"></el-option>

??</el-select>

我們這樣就可以不用vuex來去管理那些只有在模塊間復用幾次的數(shù)據(jù),而且非常方便得去取我們想要得數(shù)據(jù),連定義都省了。但是這有一個缺點。就是每次都會去重新請求這些數(shù)據(jù)。如果你不在乎這一點點瑕疵的話,我覺得用起來是完全ok的。

注意: mixins它固然是簡單的,但是注釋和引用一定要做好,不然的話新成員進入團隊大概是一臉的懵逼,而且也不利于后期的維護。也是一把雙刃劍。另外:全局mixins一定要慎用,如果不是必須要用的話我還是不建議使用。

進一步封裝組件

大家都知道組件化的最大的好處就是高度的可復用性和靈活性。但是組件怎么封裝好,封裝到什么程度讓我們更方便。這是沒有標準的答案的。我們只有根據(jù)高內(nèi)聚,低耦合的這個指導思想來對我們的業(yè)務通用組件來進行封裝,讓我們的業(yè)務頁面結構更加的簡潔,加快我們的開發(fā)效率。封裝多一點的話頁面可能會變成這樣:

<template>

??<box-content>

????<!--?頭部標題部分?-->

????<page-title>

??????<bread slot="title"?:crumbs="[{name: 'xx管理', path: '', active: true, icon: ''}, {name: 'xxxx', path: '', active: true, icon: ''}]"></bread>

????</page-title>

????<!--?表格部分?-->

????<div>

??????<base-table v-loading="loading"?:columns="headers"?:list="list"?:page-no?="pageNo"?:page-size="pageSize"?:total-count="totalCount"?@delete="deleteItm"?@change-size="handleSizeChange"?@change-page="handleCurrentChange">

??????</base-table>

????</div>

??</box-content>

</template>

有什么東西一目了然。

無狀態(tài)組件

最容易勾起我們封裝欲望的就是無狀態(tài)HTML組件,例如我們除去header, menu之后的content部分。沒有什么需要復雜的交互,但是我們每個頁面又都得寫。你說不拿它開刀拿誰開??

<template>

??<div?class="container-fluid"?:class="[contentClass]">

??????<el-row>

??????????<el-col?:span="24">

??????????????<!--?box?with?#fff bg?-->

??????????????<div?class="box">

??????????????????<div?class="box-body">

??????????????????????<slot></slot>

??????????????????</div>

??????????????</div>

??????????</el-col>

??????</el-row>

??</div>

</template>

上面這個處理非常的簡單,但是你在項目中會非常頻繁的使用過到,那么這個封裝就很有必要了。

ElementUI table組件封裝

ElementUI中得組件其實已經(jīng)封裝得很優(yōu)秀了,但是表格使用得時候還是有一堆得代碼在我看來是不需要在業(yè)務中重復寫得。封裝到靠配置來進行表格得書寫得一步我覺得就差不多了,下面是一個小demo

<template>

??<el-row>

????<el-col?:span="24">

??????<el-table?:data="list"?border size="mini"?@selection-change="handleSelectionChange"?:max-height="tableHeight"?v-bind="$attrs">?<!--?-->

????????<template v-for="(column, index) in columns">

??????????<slot name="front-slot">?</slot>

??????????<!--?序號?-->

??????????<el-table-column?:key="index"?v-if="column.type === 'selection'"?type="selection"?width="55">?</el-table-column>

??????????<!--?復選框?-->

??????????<el-table-column?:key="index"?v-else-if="column.type === 'index'"?type="index"?width="50"?label="序號">?</el-table-column>

??????????<!--?具體內(nèi)容?-->

??????????<el-table-column?:key="index"?v-else?align="left"?:label="column.title"?:width="column.width">

????????????<template slot-scope="scope">

??????????????<!--?僅僅顯示文字?-->

??????????????<label v-if="!column.hidden">?<!--?如果hidden為true的時候 那么當前格可以不顯示,可以選擇顯示自定義的slot-->

????????????????<!--?操作按鈕?-->

????????????????<label v-if="column.type === 'operate'">

??????????????????<a href="javascript:void(0)"?class="operate-button"?v-for="(operate, index) in column.operates"?:key="index"?@click="handleClick(operate, scope.row)">

????????????????????{{operate.name}}

????????????????????&nbsp;&nbsp;

??????????????????</a>

????????????????</label>

????????????????<span v-else>

??????????????????{{scope.row[column.key]}}

????????????????</span>

??????????????</label>

??????????????<!--?使用slot的情況下?-->

??????????????<label v-if="column.slot">

????????????????<!--?具名slot?-->

????????????????<slot v-if="column.slot"?:name="column.slot"?:scope="scope"></slot>

??????????????</label>

????????????</template>

??????????</el-table-column>

????????</template>

????????<!--默認的slot?-->

????????<slot/>

??????</el-table>

????</el-col>

??</el-row>

</template>



export?default?{

??name:?'base-table',

??props:?{

????// 核心數(shù)據(jù)

????list:?{

??????type:?Array,

??????default:?()?=>?[]

????},

????// columns

????columns:?{

??????type:?Array,

??????required:?true,

??????default:?()?=>?[]

????}

??},

??data?()?{

????return?{

??????tableHeight:?xxx

????}

??},

??methods:?{

????// 處理點擊事件

????handleClick(action,?data)?{

??????// emit事件

??????this.$emit(`${action.emitKey}`,?data)

????}

??}

}

使用:

<base-table v-loading="loading"?:columns="headers"?:list="list"?@view="viewCb">

??<!--?自定義的slot?-->

??<template slot="demoslot"?slot-scope="{scope}">

????<span>

??????{{scope.row}}

????</span>

??</template>

??<!--?默認的slot 如果交互很復雜 我們還可以直接使用表格內(nèi)部的組件?-->

??<el-table-column

????label="操作"

????width="200"

??>

????<template slot-scope="scope">

??????<a href="javascript:void(0)"?@click="defaultSlot(scope.row)">xxx</a>

????</template>

??</el-table-column>

</base-table>



export?default?{

??name:?'table-demo',

??data?()?{

????return?{

??????// 表格頭部配置

??????headers:?[

????????{?key:?'xxx',?title:?'測試'?},

????????{?title:?'xxx',?hidden:?true,?slot:?'demoslot'},

????????{

??????????title:?'操作',?type:?'operate',

??????????operates:?[

????????????{name:?'詳情',emitKey:?'view'}

??????????]

????????}

??????]

????}

??},

??methods:?{

????viewCb(){

??????// todo

????},

????defaultSlot(){

??????// todo

????}

??}

}

這樣封裝過的表格,應付基本的一些需求問題應該不大。至于特殊的要求可以一步一步的進行完善。

總結

這些東西并不是什么語法糖,是真正可以在項目中加快我們的效率,讓我們自己乃至整個團隊從繁雜的重復復制粘貼中解脫的方法。至于速度和質(zhì)量的問題,我是覺得使用公共組件質(zhì)量可控性會更高一些。我建議公共的東西注釋一定要寫得全面和詳細,這樣可以極大地降低我們的交流成本。至于組件的封裝還是要看你的業(yè)務。

以上觀點純屬個人意見,如有錯誤,多謝指正。

作者:markman
https://github.com/QDMarkMan/CodeBlog/edit/master/Vue/%E5%8A%A0%E5%BF%ABVue%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%BC%80%E5%8F%91%E9%80%9F%E5%BA%A6.md

感興趣的小伙伴,可以關注公眾號【grain先森】,回復關鍵詞 “vue”,獲取更多資料,更多關鍵詞玩法期待你的探索~

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 1 Webpack 1.1 概念簡介 1.1.1 WebPack是什么 1、一個打包工具 2、一個模塊加載工具 3...
    Kevin_Junbaozi閱讀 7,018評論 0 16
  • # 傳智播客vue 學習## 1. 什么是 Vue.js* Vue 開發(fā)手機 APP 需要借助于 Weex* Vu...
    再見天才閱讀 3,788評論 0 6
  • 相關概念 混合開發(fā)和前后端分離 混合開發(fā)(服務器端渲染) 前后端分離后端提供接口,前端開發(fā)界面效果(專注于用戶的交...
    他愛在黑暗中漫游閱讀 3,018評論 4 45
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對于 Vue 1.0 印象不深的內(nèi)容。關于...
    云之外閱讀 5,174評論 0 29
  • 今天語文發(fā)了一張試卷。數(shù)學考了一張試卷。上午第四節(jié)課是體育課。體育老師又讓我們背了課文。晚上回來爸爸給我買了好吃的...
    張博軒2012閱讀 127評論 0 0

友情鏈接更多精彩內(nèi)容