此篇文章不要注意排版css
經上級領導的要求,咱們公司開始步入weex的隊列,雖然如今已經處於開始階段,可是是一個好的開始,一個艱苦的開始。html
廢話很少說,咱們先聊一聊剛開始的整個過程vue
npm要求5.+,所以安裝了node8.7.0,自帶安裝了 npm 5.4.2
爲了方便切換node版本,mac上咱們能夠安裝n來管理
sudo npm n -g
n 8.7.0便已切換node
爲了 npm install 的速度快一點,設置淘寶鏡像
npm config set registry https://registry.npm.taobao.orgwebpack
1.安裝weex: sudo npm install -g weex-toolkit
2初始化工程:weex init projectName
3.運行demo
weex src/index.vue
而後便可以使用playground app二維碼掃描來查看效果了git
個人weex版本:web
首先weex號稱能夠一套代碼跑三端,那麼咱們暫且區分兩端,原生和H5.
網上巴拉巴拉查詢一通,可使用vue-router寫單頁面,可是聽說在原生APP上切換頁面的時候很卡,由於是dom級別的切換,因而,查到建議使用navigator來跳轉vue-router
而後,而後咱們就想辦法,本身封裝一個router,讓咱代碼既兼容vue-router,也兼容原生。
如下是個人項目目錄:npm
原生端route
weex-routes.js文件json
const basePath = 'http://192.168.21.75:8088/dist/views'; const routeList = [ {path: '/bankList', component: basePath + '/bankList.weex.js'}, {path: '/bank', component: basePath + '/bank.weex.js'}, {path: '/home', component: basePath + '/home/home.weex.js'}, {path: '/material', component: basePath + '/home/material.weex.js'}, {path: '/user/register', component: basePath + '/user/register/index.weex.js'}, {path: '/user/modifyPassword', component: basePath + '/user/modifyPassword.index.weex.js'}, ]; export default routeList;
web端route配置
web-routes.js文件
import bankList from 'views/bankList.vue'; import bank from 'views/bank.vue'; import home from 'views/home/home.vue'; import material from 'views/home/material.vue'; import register from 'views/user/register/index.vue'; import modifyPassword from 'views/user/modifyPassword/index.vue'; const routeList = [ {path: '/bankList', component: bankList}, {path: '/bank', component: bank}, {path: '/home/home', component: home}, {path: '/home/material', component: material}, {path: '/user/register', component: register}, {path: '/user/modifyPassword', component: modifyPassword}, ]; export default routeList;
web端H5因爲咱們作成一個單頁面,因此還須要一個入口文件
app.js文件
import VueRouter from 'vue-router'; import routeList from './web-routes.js'; Vue.use(VueRouter); const router = new VueRouter({ routes: routeList, mode: 'history' }); new Vue({ template: '<div id="root"><router-view></router-view></div>', router }).$mount('#root');
接下來就是咱們來封裝一下router了,讓咱們的代碼兼容APP和H5端,
router.js文件
import routeList from './weex-routes'; const navigator = weex.requireModule('navigator'); /** * 從weex路由表中獲取路由 * @params route String|Object */ function getWeexRoute (route) { const item = routeList.find(item => { if (item.path === route.path || route === route.path) { return item; } }); if (!item) { throw new Error(`routes路由表中不存在該路徑${route.path}`); } return item; }; const routerConfig = { install () { // H5不須要重置router屬性,直接返回 if (weex.config.env.rem) { return; } const url = weex.config.bundleUrl; const query = getQueryData(url); Object.defineProperty(Vue.prototype, "$router", { value: { push (route) { const currentRoute = getWeexRoute(route); let query = ''; if (route.query) { query = createQuery(route.query); } navigator.push({ url: currentRoute.component + query, animated: 'true' }); }, back () { if (navigator) { navigator.pop(); } } }, configurable: false }); Object.defineProperty(Vue.prototype, '$route', { configurable: false, value: { query: query, fullPath: '', name: '', params: {}, path: '', hash: '', } }); } } Vue.use(routerConfig); // object 轉 URL 參數 function createQuery (obj) { let url = '?'; for (let key in obj) { if (obj[key] !== null) { url += (key + '=' + encodeURIComponent(obj[key]) + '&'); } } return url.substring(0, url.lastIndexOf('&')); }; // 'xxx.js?name=aa' 轉 {name: 'aa'} function getQueryData (url) { url = url.substring(url.indexOf('.js?') + 3); var result = {}; if (url.indexOf("?") != -1) { var str = url.substr(1); var strs = str.split("&"); for (var i = 0; i < strs.length; i++) { result[strs[i].split("=")[0]] = decodeURIComponent(strs[i].split("=")[1]); } } return result; };
ok基礎設施已大功告成,咱們須要在咱們的業務代碼中使用router了
// 首先須要引入咱們的router.js import '../../router.js'; this.$router.push({path: '/material', query: this.form}); // 當跳轉到material.vue中咱們則能夠直接獲取url中的參數了,此法兼容原生和H5 import '../../router.js'; this.query = this.$route.query;
基礎的配置咱們已經操做完畢,接下來要配置webpack了
咱們須要一個build xx.wexx.js的webpack配置
和一個web的單頁的webpack配置
webpack.web.js配置
const ip = require('ip').address(); const path = require('path'); const chalk = require('chalk'); const webpack = require('webpack'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); console.log('server is running! Please open ' + chalk.green('http://' + ip + ':8080/')); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin'); const isProd = process.env.NODE_ENV === 'production'; module.exports = function() { const config = { entry: { app: './src/app.js' }, output: { path: path.join(__dirname, './dist'), filename: '[name].[hash:7].web.js', }, resolve: { extensions: ['*', '.vue', '.js'], alias: { 'src': path.join(__dirname, './src'), 'views': path.join(__dirname, './src/views'), 'services': path.join(__dirname, './src/services'), 'utils': path.join(__dirname, './src/utils'), 'constants': path.join(__dirname, './src/constants'), 'assets': path.join(__dirname, './src/assets'), } }, devtool: 'source-map', module: { rules: [ { test: /\.vue(\?[^?]+)?$/, loader: 'vue-loader', }, { test: /\.html$/, loader: 'raw-loader', }, { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] }, plugins: [ new webpack.BannerPlugin({ banner: '// { "framework": ' + ('.vue' === '.vue' ? '"Vue"' : '"Weex"') + '} \n', raw: true, exclude: 'Vue' }), new ScriptExtHtmlWebpackPlugin({ defaultAttribute: 'defer' }) ] }; if (!isProd) { config.plugins.push( new HtmlWebpackPlugin({ template: 'web/index.dev.html', title: 'Hello Weex', isDevServer: true, chunksSortMode: 'dependency', inject: 'head' }) ); config.devServer = { compress: true, host: '0.0.0.0', port: '8080', historyApiFallback: true, public: ip + ':8080', watchOptions: { aggregateTimeout: 300, poll: 1000 } }; } else { // 抽取vue文件css config.module.rules[0].options = { loaders: { css: ExtractTextPlugin.extract({ use: ['css-loader'], fallback: 'vue-style-loader' }) } }; config.plugins.push( new ExtractTextPlugin('[name].[hash:7].css'), new HtmlWebpackPlugin({ template: 'web/index.html', inject: true, }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ) } return config; }
原生端的webpack.config.js配置:
const pathTo = require('path'); const fs = require('fs-extra'); const webpack = require('webpack'); const entry = {}; const weexEntry = {}; const vueWebTemp = 'temp'; const hasPluginInstalled = fs.existsSync('./web/plugin.js'); var isWin = /^win/.test(process.platform); function getEntryFileContent(entryPath, vueFilePath) { let relativePath = pathTo.relative(pathTo.join(entryPath, '../'), vueFilePath); let contents = ''; if (hasPluginInstalled) { const plugindir = pathTo.resolve('./web/plugin.js'); contents = 'require(\'' + plugindir + '\') \n'; } if (isWin) { relativePath = relativePath.replace(/\\/g,'\\\\'); } contents += 'var App = require(\'' + relativePath + '\')\n'; contents += 'App.el = \'#root\'\n'; contents += 'new Vue(App)\n'; return contents; } var fileType = ''; function walk(dir) { dir = dir || '.'; const directory = pathTo.join(__dirname, 'src', dir); fs.readdirSync(directory) .forEach((file) => { const fullpath = pathTo.join(directory, file); const stat = fs.statSync(fullpath); const extname = pathTo.extname(fullpath); if (stat.isFile() && extname === '.vue' || extname === '.we') { if (!fileType) { fileType = extname; } if (fileType && extname !== fileType) { console.log('Error: This is not a good practice when you use ".we" and ".vue" togither!'); } const name = pathTo.join(dir, pathTo.basename(file, extname)); if (extname === '.vue') { const entryFile = pathTo.join(vueWebTemp, dir, pathTo.basename(file, extname) + '.js'); fs.outputFileSync(pathTo.join(entryFile), getEntryFileContent(entryFile, fullpath)); entry[name] = pathTo.join(__dirname, entryFile) + '?entry=true'; } if (fullpath.includes('/views')) { weexEntry[name] = fullpath + '?entry=true'; } } else if (stat.isDirectory() && file !== 'build' && file !== 'include') { const subdir = pathTo.join(dir, file); walk(subdir); } }); } walk(); // web need vue-loader const plugins = [ new webpack.optimize.UglifyJsPlugin({minimize: true}), new webpack.BannerPlugin({ banner: '// { "framework": ' + (fileType === '.vue' ? '"Vue"' : '"Weex"') + '} \n', raw: true, exclude: 'Vue' }) ]; const weexConfig = { entry: weexEntry, output: { path: pathTo.join(__dirname, 'dist'), filename: '[name].weex.js', }, module: { rules: [ { test: /\.js$/, use: [{ loader: 'babel-loader', }], exclude: /node_modules(?!\/.*(weex).*)/ }, { test: /\.vue(\?[^?]+)?$/, use: [{ loader: 'weex-loader' }] }, { test: /\.we(\?[^?]+)?$/, use: [{ loader: 'weex-loader' }] } ] }, plugins: plugins, }; module.exports = weexConfig;
package.json配置:
"build": "rm -rf dist && cross-env NODE_ENV=production webpack --config webpack.web.js && webpack --config webpack.config.js", "web1": "webpack --config webpack.web.js --watch", "web2": "webpack-dev-server --config webpack.web.js --progress --watch --open", "web": "rm -rf dist&npm run web1&npm run web2"
打包執行 npm run build,就會把weex和H5的文件都給生產到dist目錄中了
.weex文件是原生的,.css .web index.html是H5的
還須要注意的地方:因爲咱們也是剛開始接觸weex,但願這這只是一個參考案例,畢竟咱們也不是高手。