前言:欢迎前端的小伙伴们前来围观、学习借鉴,如果你是后端、测试和其他的小伙伴也没关系,如果自己也想玩一下前端,想搭建一个前端的框架,那么不妨静下心来看看这篇文章。如果你不是从事开发工作的人员,内容可能相对而言比较枯燥,但是如果想找错别字,也不妨进来看看。

初衷:有的前端的小伙伴要说了,vue-cli不是已经帮我们封装好了webpack(打包)吗?为什么,还要进行二次的搭建和封装呢?我想说的是,是的这些很基础的配置vue-cli都帮我们做好了,但是针对手机端样式初始化,axios的请求封装,常用的工具包类封装,vuex模块化的处理,以及开发、测试、正式环境变量的拆分配置,webpack打包优化配置,手机端响应式的处理,手机端引入第三方UI框架vant的更好的方法等等都没有给我们搭建,因为不同项目可能有不同的方式,我这里介绍的是一种大众的、通用的一些框架:vue-cli+vue-router+vuex+axios+vant。

目的:教你如何手动搭建属于自己的前端手机项目。

废话不多说,直接上干货。

第一步: vue-cli初始化项目(相信很多前端小伙伴这一步操作都不难)

npm install -g @vue/clivue create my-project

注:这里的my-project自己可以按照自己的项目名称来定义
如果你没有安装成功,那么需要把nodejs安装一下。

第二步:配置全局环境变量

需要我们在根目录创建四个文件:.env、.env.dev、.env.test、.env.pro
目的:我们不可能反复的去更改配置文件,而是通过运行不同的指令来调用同变量不同环境的值。

//.env 和 .env.dev 内容一样
VUE_APP_NODE_ENV="development"
VUE_APP_API="http://public-api-v1.aspirantzhang.com/"
VUE_APP_VERSION = "d-1.0"//.env.test
VUE_APP_NODE_ENV="test"
VUE_APP_API="https://wwww.baidu.com/production"
VUE_APP_VERSION = "t-1.0"//.env.pro
VUE_APP_NODE_ENV="production"
VUE_APP_API="https://wwww.baidu.com/production"
VUE_APP_VERSION = "p-1.0"

这四个配置文件是结合package.json来使用的,启动不同的命令,执行不同变量参数

"scripts": {"dev": "vue-cli-service serve","test": "vue-cli-service serve --mode test","pro": "vue-cli-service serve --mode pro","build:dev": "vue-cli-service build --mode dev","build:test": "vue-cli-service build --mode test","build:pro": "vue-cli-service build --mode pro","lint": "vue-cli-service lint"
},

第三步:路由配置

在配置路由之前我创建了两个页面:
首页:src/views/Home/Home.vue
列表页:src/views/List/List.vue

1.创建src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'Vue.use(VueRouter)const routes = [{path: '/',redirect: {name: 'home'}},{path: '/home',name: 'home',meta: {title: '首页',},component: () => import(/* webpackChunkName: "Home" */ '../views/Home/Home.vue') // 首页},{path: '/list',name: 'list',meta: {title: '列表页面',},component: () => import(/* webpackChunkName: "List" */ '../views/List/List.vue') // 列表页面}
]const router = new VueRouter({base: process.env.BASE_URL,routes
})
router.beforeEach((to, from, next) => {/* 路由发生变化修改页面title */if (to.meta.title) {document.title = to.meta.title}next()
})export default router

2.在入口文件main.js中引用router

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

3.在App.vue文件中通过router-view来获取路由指向的页面,把页面和路由关联起来

<template><div id="app"><router-view /></div>
</template><script>
export default {name: 'App',created(){console.log(process.env.VUE_APP_NODE_ENV, '-', process.env.VUE_APP_VERSION)}
}
</script>

第四步:vuex模块处理配置

1.创建src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import VuexPersistence from 'vuex-persist'
import home from './modules/home'
import list from './modules/list'const vuexLocal = new VuexPersistence({storage: window.localStorage,modules: ["home"]
})
Vue.use(Vuex)const store = new Vuex.Store({strict: process.env.NODE_ENV !== 'production',modules: { home, list },plugins: [vuexLocal.plugin]
})export default store

2.创建src/store/modules/home.js

export default {namespaced: true,state: {list: [],visible: false,firstName: 'Sunny',lastName: 'Fan'},mutations: {MGetList(state, data){state.list = data},MChangeVisible(state, value){state.visible = value}},actions: {// 异步请求接口数据AGetList ({ commit }, params) {const url = '/users'const error = '获取数据失败'return $http.get(url, params).then(res => {const { data } = res// commit 去同步更改state里面的数据return commit('MGetList', data)}).catch(e => {return Promise.resolve(e && e.statusText || error)})},},getters: {getFullName: state => {return state.firstName +'----'+ state.lastName}}
}

3.创建src/store/modules/list.js 这个参考2即可
4.在入口文件mian.js中引入store/index.js

import Vue from 'vue'
import router from './router'
import store from './store'
import Axios from '@/utils/Axios'
import App from './App.vue'
import 'lib-flexible/flexible' // 根据窗口不同,给html设置不同的font-size值
import './utils/vant' // 引入局部ui
import './assets/css/common.less'
import Vconsole from 'vconsole'Vue.config.productionTip = false// 在开发环境和测试环境打开console方便在真机上查看日志、追踪问题
const environment = process.env.VUE_APP_NODE_ENV;
if(environment==='development'||environment==='test'){const vConsole = new Vconsole()Vue.use(vConsole)
}// vue内部全局注入
Vue.use({install (vue) {Object.assign(vue.prototype, {$axios: Axios,$store: store})}
})new Vue({router,store,render: h => h(App),
}).$mount('#app')

第五步:手机端响应式配置,以及初始化样式、vant样式框架引入(根据不同屏幕放大缩小适配)

1.在src创建assets/common.less

*{padding: 0;margin: 0;box-sizing: border-box;touch-action: auto;-webkit-overflow-scrolling:touch;
}
html, body {height:100vh;width: 100vw;margin: 0; padding:0;
}

并且在我们的入口文件:main.js中引入common.less文件

import './assets/css/common.less'

2.安装适配依赖

  yarn add lib-flexible autoprefixer postcss-pxtorem babel-plugin-import

3.根据依赖进行相关的配置
在项目的根目录创建postcss.config.js

const autoprefixer = require('autoprefixer')
const pxtorem = require('postcss-pxtorem')module.exports = ({ file }) => {let rootValue// vant 37.5 [link](https://github.com/youzan/vant/issues/1181)// if (file && file.dirname && file.dirname.indexOf('vant') > -1 && file.dirname.indexOf('swiper') > -1) {if (file && file.dirname && file.dirname.indexOf('vant') > -1) {rootValue = 37.5} else {rootValue = 75}return {plugins: [autoprefixer(),pxtorem({rootValue: rootValue,propList: ['*'],selectorBlackList: ['.swiper'], // 要忽略的选择器并保留为px。minPixelValue: 0})]}
}

4.根据vant的官网文档,我们通过在babel.config.js文件中配置来引入vant的样式

module.exports = {presets: ['@vue/cli-plugin-babel/preset'],plugins: [['import', {libraryName: 'vant',libraryDirectory: 'es',style: true}, 'vant']]
}

5.页面调用
<van-button type="info">按钮</van-button>
6.页面适配,在main.js中引入lib-flexible依赖

import 'lib-flexible/flexible' // 根据窗口不同,给html设置不同的font-size值

第六步:vant UI的引入(按需引入,降低打包体积)

//通过 npm 安装
npm i vant -S//通过 yarn 安装
yarn add vant
  1. 在src创建utils/vant.js
import Vue from 'vue'
import {Loading, Lazyload, Toast, Dialog,} from 'vant'// 默认vant组件
[Loading, Lazyload, Toast, Dialog,].forEach(item => Vue.use(item))// 先预制,后期做统一调整
Object.assign(window, {Toast, Dialog
})

从代码我们能看出来,每个组件都是按需引入,大大的降低了打包的体积,并且把Toast和Dialog注入到了window全局变量里面,为了方便我们直接调用。
2.解决vant样式适配问题,查看上面的postcss.config.js即可
3.在入口文件main.js 引入

import './utils/vant' // 引入局部ui

第七步:Axios的封装(公共头部、异常、不同请求方式配置处理)

1.创建src/utils/request.js

import axios from 'axios'const codeMessage = {200: '服务器成功返回请求的数据。',201: '新建或修改数据成功。',202: '一个请求已经进入后台排队(异步任务)。',204: '删除数据成功。',400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',401: '用户没有权限(令牌、用户名、密码错误)。',403: '用户得到授权,但是访问是被禁止的。',404: '发出的请求是不存在的,服务器没有进行操作。',406: '请求的格式不可得。',410: '请求的资源被永久删除。',422: '当创建一个对象时,发生一个验证错误。',500: '服务器发生错误,请检查服务器。',502: '网关错误。',503: '服务不可用,服务器暂时过载或维护。',504: '网关超时。'
}
const baseURL = process.env.VUE_APP_NODE_ENV == 'development' ? '/api' : process.env.VUE_APP_API
const instance = axios.create({baseURL
})
class Request {constructor(baseURL) {this.baseURL = baseURLthis.queue = {}this.timeout = 5000}// 检查返回状态checkStatus (response) {const responseData = response.data// 服务器返回默认结果if (response && (response.status === 200 || response.status === 304 || response.status === 400)) {// 后台自定义错误// 正常if (responseData.status == 0) {return responseData}// 登录过期if (responseData.errorCode === 402 || responseData.status === 401) {return Promise.reject(errorText)}return Promise.reject(responseData)}// 服务器错误const errorText = response && (codeMessage[response.status] || response.statusText)Promise.reject(response)}// 拦截器interceptors (instance, scope) {// 请求拦截instance.interceptors.request.use(config => {config.baseURL = baseURL;config.scope = scopereturn config}, error => {return Promise.reject(error)})// 响应拦截instance.interceptors.response.use(res => {return res}, error => {let errorInfo = error.responseif (!errorInfo) {try {const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error))errorInfo = {statusText,status,request: { responseURL: config.url }}} catch (e) {errorInfo = error}}return Promise.reject(errorInfo)})}// 失败error (e) {return Promise.reject(e)}setRequest (method, url, data, scope, file = false) {this.interceptors(instance, scope)const options = { method, url }let contentType = ''if (file) {contentType = 'multipart/form-data'} else if (method == 'post') {contentType = 'application/json'} else {contentType = 'application/x-www-form-urlencoded; charset=UTF-8'}const headers = {'X-Requested-With': 'XMLHttpRequest','Content-Type': contentType,// token: store.state.user.token || 1}Object.assign(options, {headers,[method == 'post' ? 'data' : 'params']: data})return instance(options).then(this.checkStatus).catch(this.error)}// post 请求封装post (url, data, scope) {return this.setRequest('post', url, data, scope)}// get  请求封装get (url, data, scope) {return this.setRequest('get', url, data, scope)}// post 请求封装POST (url, data, scope) {return this.setRequest('post', url, data, scope).then(this.success)}// get  请求封装GET (url, data, scope) {return this.setRequest('get', url, data, scope).then(this.success)}// 文件File (url, data, scope) {return this.setRequest('post', url, data, scope, true).then(this.fileSuccess)}success (da) {return da.data}fileSuccess (da) {return da}
}export default Request

2.创建src/utils/Axios.js

import Vue from "vue";
import Request from './request'
//import config from '@/config'
const Axios = new Request()
Plugin.install=(Vue)=>{Vue.prototype.$http = Axios
}
Object.assign(window,{$http:Axios
})
Vue.use(Plugin);
export default Axios

第八步:vue.config.js配置(针对webpack进行了封装)

这一步我们进行了,icon图标雪碧图处理,打包文件哈希命名,解决缓存问题,本地接口代理处理,打包引入cdn文件,路径过长别名处理等等
1.vue.config.js

const path = require('path')
const SpritesmithPlugin = require('webpack-spritesmith')// 雪碧图
const TerserPlugin = require('terser-webpack-plugin')
const devServer = require('./server')
const CompressionPlugin = require('compression-webpack-plugin')const cdn = {// 开发环境dev: {css: [],js: []},// 生产环境build: {css: [],js: ['https://lib.baomitu.com/vue/2.6.11/vue.min.js','https://lib.baomitu.com/vue-router/3.2.0/vue-router.min.js','https://lib.baomitu.com/vuex/3.5.1/vuex.min.js','https://lib.baomitu.com/axios/0.19.2/axios.min.js','https://lib.baomitu.com/hls.js/0.14.3/hls.min.js']}
}
// 打包排除包,通过cdn加载
const externals = {'vue': 'Vue','vuex': 'Vuex','axios': 'axios','hls.js': 'hls.js','vue-router': 'VueRouter'
}// 雪碧图的自定义模板
const templateFunction = function (data) {var shared = '.icon-sprite { display: inline-block; background-image: url(I); background-size: Dpx Hpx; }'.replace('I', data.sprites[0].image).replace('D', data.sprites[0].total_width / 2).replace('H', data.sprites[0].total_height / 2)var perSprite = data.sprites.map(function (sprite) {return '.icon-N { width: Wpx; height: Hpx; background-position: Xpx Ypx; }'.replace('N', sprite.name.replace(/_/g, '-')).replace('W', sprite.width / 2).replace('H', sprite.height / 2).replace('X', sprite.offset_x / 2).replace('Y', sprite.offset_y / 2)}).join('\n')return shared + '\n' + perSprite
}
const configureWebpackData = {resolve: {alias: {// 别名vue$: 'vue/dist/vue.esm.js','@': resolve('src'),'@api': resolve('src/api'),'@utils': resolve('src/utils'),'@style': resolve('src/assets/css'),'@images': resolve('src/assets/images'),'@views': resolve('src/views')}},plugins: [new SpritesmithPlugin({src: {cwd: path.resolve(__dirname, './src/assets/icon'),glob: '*.png'},target: { // 输出雪碧图文件及样式文件,这个是打包后,自动生成的雪碧图和样式image: path.resolve(__dirname, './src/assets/images/sprite.png'),css: [[path.resolve(__dirname, './src/assets/css/sprite.less'), {// 引用自己的模板format: 'function_based_template'}]]},customTemplates: { // 自定义模板入口function_based_template: templateFunction},apiOptions: { // 样式文件中调用雪碧图地址写法cssImageRef: '../images/sprite.png'},spritesmithOptions: { // 让合成的每个图片有一定的距离padding: 20}})]}
function resolve (dir) {return path.join(__dirname, './', dir)
}module.exports = {outputDir: "dist",assetsDir: 'assets',publicPath: './',pages: {index: {entry: './src/main.js',template: path.join(__dirname, 'public/index.html'),filename: 'index.html',cdn: process.env.VUE_APP_NODE_ENV === 'production' && cdn.build || cdn.dev,title: '  '}},lintOnSave: false, // 是否开启编译时是否不符合eslint提示devServer,configureWebpack: config => {configureWebpackData.externals = process.env.VUE_APP_NODE_ENV === 'production' && externals || {};if (process.env.VUE_APP_NODE_ENV === 'production' || process.env.VUE_APP_NODE_ENV === 'devproduction') {config.plugins.push(new TerserPlugin({terserOptions: {ecma: undefined,warnings: false,parse: {},compress: {drop_console: true,drop_debugger: false,pure_funcs: ['console.log'] // 移除console}}}))}if (process.env.VUE_APP_NODE_ENV === 'production') {configureWebpackData.plugins.push(new CompressionPlugin({test: /\.js$|\.html$|\.css/,threshold: 10240,deleteOriginalAssets: false}))}return configureWebpackData},chainWebpack: config => {config.output.filename('assets/js/[name].[hash].js').end()config.output.chunkFilename('assets/js/[name].[hash].js').end()},productionSourceMap: false,css: {// extract: true,sourceMap: false,// modules: false,requireModuleExtension: true,loaderOptions: {}}
}

2.server.js 主要配置代理相关信息

module.exports = {host: '0.0.0.0',port: 8000,https: false,hotOnly: false,proxy: {'^/api': {// 测试环境target: process.env.VUE_APP_API, changeOrigin: true, // 是否跨域pathRewrite: {'^/api': '' // 需要rewrite重写的,  // /mock}}}
}

第九步:常见工具类的配置(时间、正则、公共方法、数据字典)

1.创建src/utils/index.js

//校验输入文字为纯数字
export function validNumber(value) {const reg = /^\d+$/;return reg.test(value);
}//校验输入的文字 --综合搜索
export function validText(value) {const reg = /^([\u4E00-\u9FA5])*$/;return reg.test(value);
}//电话号码正则函数
export function checkPhone(value) {const reg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/;return reg.test(value);
}//邮箱正则函数
export function checkEmail(value) {const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;return reg.test(value);
}//2-10位中英文
export function checkUserName(value) {const reg = /^[\u4E00-\u9FA5A-Za-z]{2,10}$/;return reg.test(value);
}//去除空格
export function removeSpace(value) {const reg = /\s+/g;return value.replace(reg, "");
}//为空或全部为空格
export function checkSpace(value) {const reg = /^[ ]*$/;return reg.test(value);
}//判断密码大于6位,数字、字母大小写组合
export function checkPassWord(value) {let regNumber = /\d+/;let regString = /[a-zA-Z]+/;return regNumber.test(value) && regString.test(value) && value.length >= 8 && value.length <= 20;
}//获取周几
export function weeks(day) {let myDate = day ? new Date(day) : new Date();let wk = myDate.getDay();switch (wk) {case 0:return '星期日';case 1:return '星期一';case 2:return '星期二';case 3:return '星期三';case 4:return '星期四';case 5:return '星期五';case 6:return '星期六';}return wk;
}export function checkIdCard(value) {const idCardNo = value;if(idCardNo.length === 18) {const birStr = value.substr(6, 8);const sexFlag = idCardNo.charAt(16) - 0; //奇数男 偶数女const sexfromIDcard = sexFlag % 2; //1男 0女return {sex: sexfromIDcard===1?0:1, birStr};} else if(idCardNo.length === 15) {const birStr = '19' + value.substr(6, 6);const sexFlag2 = idCardNo.charAt(14) - 0; //奇数男 偶数女const sexfromIDcard2 = sexFlag2 % 2; //1男 0女return {sex: sexfromIDcard2===1?0:1, birStr};}
}// 获取当前时间年月日时分秒
export function getNowData(type) {let date = new Date();let year = date.getFullYear();let month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();let lastDay = date.getDate() - 1 < 10 ? '0' + (date.getDate() - 1) : date.getDate() - 1;let hour = date.getHours();let minute = date.getMinutes();let second = date.getSeconds();switch (type) {case 1:return `${year}-${month}-${day}`;case 2:return `${year}-${month}-${day} ${hour}:${minute}:${second}`;case 3:return day;case 4:return `${year}.${month}`;case 5:return `${year}-${month}-${lastDay}`;default:return `${year}-${month}-${day}`;}
}//数组排序
export function compare(property) {return function (a, b) {var value1 = a[property];var value2 = b[property];return value1 - value2;};
}

第十:总结

自己抽了一天时间,一遍搭建,一遍写文档,反复修改,可能里面还有很多需要完善地方,后期我会出整个的搭建的过程的视频,帮助大家更加直观的去理解和学习。
码字不易,如果有帮助到自己的地方或者看后对自己学习前端知识所有提升,请关注一下我的公众号,后期会有更多精品的内容推出,写出来和大家一起分享学习。

走过路过不要错过,既然都看到这个地方了,那就留下一个评论和点赞吧。

源码地址:https://github.com/fx35792/vue-mobile-template
原文地址:http://blog.sunnyfanfan.com/articles/2020/09/24/1600938805892.html
参考文献:
https://cli.vuejs.org/
https://vant-contrib.gitee.io/vant/#/zh-CN/

手把手教你通过vue-cli搭建手机端框架相关推荐

  1. 手把手教你从0开始搭建一个vue项目(完结)

    前言 上一节webpack实战之(手把手教你从0开始搭建一个vue项目)最后我们完成了css样式的配置: webpack.config.js: const path = require("p ...

  2. 适合新手:手把手教你用Go快速搭建高性能、可扩展的IM系统(有源码)

    本文为开源工程:"github.com/GuoZhaoran/fastIM"的配套文章,原作者:"绘你一世倾城",现为:猎豹移动php开发工程师,感谢原作者的技 ...

  3. 手把手教你腾讯云搭建RUOYI系统

    手把手教你腾讯云搭建RUOYI系统 前置准备 腾讯云配置 1 服务器准备 1.1 腾讯云购买地址: 1.2 配置 开放端口 2 软件安装 2.1 MySQL在线安装 2.2 Redis 安装 2.3 ...

  4. vue = 什么意思_记录使用@vue/cli搭建Vue3项目完整流程

    最近发现vue两大UI框架Element UI和Ant Design Vue都已经支持Vue3了,如果再不学习Vue3就落伍了,此文章记录下使用@vue/cli搭建Vue3项目完整流程. 1 安装vu ...

  5. stm32l0的停止模式怎么唤醒_手把手教你怎么利用旧电脑搭建NAS组建自己的黑群晖...

    手把手教你怎么利用旧电脑搭建NAS组建自己的黑群晖 Synology 群晖科技(Synology )创立于 2000 年,自始便专注于打造高效能.可靠.功能丰富且绿色环保的 NAS 服务器,是全球少数 ...

  6. cli vue 卸载_记录使用@vue/cli搭建Vue3项目完整流程

    最近发现vue两大UI框架Element UI和Ant Design Vue都已经支持Vue3了,如果再不学习Vue3就落伍了,此文章记录下使用@vue/cli搭建Vue3项目完整流程. 1 安装vu ...

  7. 手把手教你直播平台怎么搭建

    手把手教你直播平台怎么搭建 后端项目初始化 1.全局安装express脚手架 额,这个应该是属于准备工作的.给忘记了,那就凑合放在这里吧,别打我,我知道错了,但我就是不改[狗头保命] cnpm ins ...

  8. ESP8266 Non-OS SDK 开发之旅 基础篇① 初识 Non-OS SDK,史上超级详细手把手教小白20分钟快速搭建SDK软件开发环境,完成第一个例子Hello World!

    文章目录 1.前言 2. SDK概述 2.1 SDK使用流程 2.2 ESP8266 HDK -- 硬件开发工具 2.3 ESP8266 SDK -- 软件开发工具包 2.3.1 Non-OS SDK ...

  9. vue 手机端答题页面_从0开始,手把手教你用Vue开发一个答题App

    项目演示 项目源码 配套讲解视频 教程说明 本教程适合对Vue基础知识有一点了解,但不懂得综合运用,还未曾使用Vue从头开发过一个小型App的读者.本教程不对所有的Vue知识点进行讲解,而是手把手一步 ...

最新文章

  1. linux r服务安装失败,R包:RCurl和curl包在Linux上安装失败
  2. AngularJS中实现无限级联动菜单(使用demo)
  3. Spring Boot 2.4发布了,但 Spring Cloud 用户不推荐着急升级
  4. php dubbo 接口测试工具,dubbo服务自动化测试搭建
  5. 【树莓派】首发树莓派4原型机接口参数曝光
  6. 【Linux】【服务器】 CentOS7下安装Redis详细过程步骤
  7. 用计算机做科学计算是绝对精确的吗,科学计算与数学建模 - osc_3gfjojb2的个人空间 - OSCHINA - 中文开源技术交流社区...
  8. JEMTER简单的测试计划
  9. python3示例_Python3 实例(七)
  10. SQL中where 1 = 1的用处
  11. django-数据的插入-利用pymysql
  12. 开发打开设置洁面_用了两到三年的华为手机,一键打开quot;开发者选项quot;,帮助性能加速...
  13. Centos7安装NVIDIA的驱动的坑
  14. Java爬虫需要的包_java爬虫需要的jar包
  15. 华为手机6130失效_华为手机的拨号键这5个功能,用过的人都拍手叫好,绝不虚吹...
  16. VMware卸载不干净导致的重装失败(100%解决问题)
  17. 如何查看linux是grub还lilo,linux中LILO及GRUB配置实例
  18. 《庄子·杂篇·庚桑楚第二十三》
  19. linux设置apn脚本apn,LINUX 4G pppd接入点设置
  20. Hacked【黑客】手游攻略

热门文章

  1. PHP多维数组按照键进行排序(对KEY按ASSIIC码排序)
  2. 人生只有一件事:坚持正确改正错误
  3. 电梯相框广告怎么选择其材质
  4. codeforces #309 div2
  5. scada与MySQL连接_SCADA系统与实时数据库数据同步
  6. 手把手教你开发photoshop面板插件(附demo和工具)
  7. 计算机主板上的bios与cmos的关系是,bios cmos 关系是什么?有什么区别?
  8. Androidnbsp;学习论坛博客及网站推荐(…
  9. Android studio低版本让3.0编译通过,更好的用studio看代码(找不到原作者那个网址链接了,望见谅!)
  10. Ajax传递数组对象