Giter VIP home page Giter VIP logo

blog's Introduction

Hi there 👋

I'm zhengzhuang (郑壮) .

  • 👨‍💻 北京 · 前端开发工程师
  • 🏷️ React、Vue、JavaScript、TypeScript、Next.js、Flutter
  • 低代码、埋点、组件库、脚手架、前端各种基建
  • 👯 我正在寻找合作的机会...
  • 📫 微信: zhuang960108
  • Contact with me via Telegram:https://t.me/zh_zhuang

我的博客

blog's People

Contributors

zhengzhuang96 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

blog's Issues

vue-cli3.0项目中使用vw——相比flexible更原生的移动端解决方案

亲测,对于vue3.x来说,适配最好

vw 与 vh单位,以viewport为基准,1vw 与 1vh分别为window.innerWidth 与 window.innerHeight的百分之一。

安装
命令行输入:

yarn add postcss-px-to-viewport 

npm i postcss-px-to-viewport -save -dev

配置
package.json中,在postcss中添加代码:

"postcss": {
    "plugins": {
        "autoprefixer": {},
        "postcss-px-to-viewport": {
            "viewportWidth": 750,
            "minPixelValue": 1
        }
    }
},

配置项:

"viewportWidth": 750,   // 设计稿的宽度  
"unitPrecision": 3,     // px转成vw、vh后小数点保留的位数 
"minPixelValue": 1,     // 不转化为vw的最小px值

使用场景
vw与vh会在pc与移动端均产生效果,而不像flexible只会转换一定宽度(记得是750px)以下设备的px为rem,因此若设计稿为移动端而生,全权使用vw单位会使得页面在pc端出现字体过大等现象,需酌情处理,根据应用场景自行选择

兼容性
vw/vh 单位其实出现比较早了,只是以前支持性不太好,现在随着浏览器的发展,大部分(92%以上)的浏览器已经支持了vw/vh,

Ubuntu下安装AndroidStudio

写在前面

接触Ubuntu已经有一段时间了,对于使用Ubuntu进行程序开发,在爽不过了,接下来把自己学习的Android-studio在Ubuntu系统下的安装过程记录下来,进行习惯性的记忆

步骤

第一步:安装JDK

打开终端
使用快捷键:Ctrl+Alt+T

使用如下三条命令,安装JDK

sudo add-apt-repository ppa:webupd8team/java 
sudo apt-get update 
sudo apt-get install oracle-java8-installer 

按照上面三条指令进行以此安装
1
2
3
4

按照命令依次安装,如图所是,证明你就安装成功拉,嘻嘻!

检验JDK是否安装成功

输入:

java -version

5

安装AndroidStudio

下载AndroidStudio

打开“https://developer.android.google.cn/studio/“链接,下载AndroidStudio

6

解压AndroidStudio

将Android复制到某个位置,并执行unzip指令解压
7

将解压好的文件移动到指定位置

本文移动到:/home/zhengzhuang/software 下
8

打开终端,cd进入android-studio/bin目录“./studio.sh”进行安装

9

其他配置如Windows

设置使用之前配置
10

设置是否代理,我选择取消
11

安装向导,依次按照步骤安装

12
13
14
15
16
17

到此步骤,就大功告成啦,开始新建项目吧!

新建项目

Flutter路由项目实战之fluro

github: https://github.com/zhengzhuang95/flutter_fluro

关于flutter路由,在小项目中,就按照原生写法,但是在大型项目中,这样的我就不会进行推荐,我这里使用的fluro路由管理方案,大型项目中非常nice,现在开始啥也不说了,看我操作就行了

fluro: ^1.5.1

注:自认为是Flutter最亮,最时髦,最酷的路由器。

在大型项目中,你要问我什么叫大型,我感觉超过20就算了吧,具体什么叫大型,我也不知道,哈哈哈

首先呢,在项目中新建一个routers文件夹,与main.dart同级,这个文件夹就是我们的路由文件夹,建好之后,我们开始进行创建路由

1:新建application.dart

import 'package:fluro/fluro.dart';
class Application {
    static Router router;
}

2:新建routes.dart

这个页面就配置我们的路由调转链接模块

import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import './router_handler.dart';

class Routes {
    static String root = '/';
    static String indexPage = '/indexPage';
    static String normalPage = '/normalPage';
    static String routingReference = '/routingReference';
    static String login = '/login';
    static void configureRoutes(Router router) {
        router.notFoundHandler = new Handler(
            handlerFunc: (BuildContext context, Map<String, List<String>> params) {
                print('ERROR====>ROUTE WAS NOT FONUND!!!'); // 找不到路由,跳转404页面
                print('找不到路由,404');
            },
        );

        // 路由页面配置
        router.define(indexPage, handler: indexPageHanderl);
        router.define(normalPage, handler: normalPageHanderl);
        router.define(routingReference, handler: routingReferenceHanderl);
        router.define(login, handler: loginHanderl);
    }
}

3:新建router_handler.dart

handler就是每个路由的规则,编写handler就是配置路由规则,比如我们要传递参数,参数的值是什么,这些都需要在Handler中完成。

import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import 'package:flutter_fluro/pages/index_page.dart';
import 'package:flutter_fluro/pages/login.dart';
import 'package:flutter_fluro/pages/normal_page.dart';
import 'package:flutter_fluro/pages/routing_reference.dart';
// 首页
Handler indexPageHanderl = Handler(  
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {    
        return IndexPage();  
    },
);

// 正常路由跳转
Handler normalPageHanderl = Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
        return NormalPage();
    }
);

// 路由传参
Handler routingReferenceHanderl = Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
        String id = params['id'].first;
        return RoutingReference(id: id);
    }
);

// 登陆页面
Handler loginHanderl = Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
        return Login();
    }
);

4:新建navigator_util.dart

这个里面主要是进行路由跳转方法的公共书写

import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import 'package:maitianshanglv_driver/pages/app_common_module/login.dart';
import 'package:maitianshanglv_driver/pages/index_page.dart';
import './application.dart';
import './routes.dart';

class NavigatorUtil {  
    // 返回  
    static void goBack(BuildContext context) {    
        /// 其实这边调用的是 
        Navigator.pop(context);    
        Application.router.pop(context);  
    }
    
    // 带参数的返回
    static void goBackWithParams(BuildContext context, result) {
        Navigator.pop(context, result);
    }

    // 路由返回指定页面
    static void goBackUrl(BuildContext context, String title) {
        Navigator.popAndPushNamed(context, title);
    }

    // 跳转到主页面
    static void goHomePage(BuildContext context) {
        Application.router.navigateTo(context, Routes.homePage, replace: true);
    }
    
    /// 跳转到 转场动画 页面 , 这边只展示 inFromLeft ,剩下的自己去尝试下,
    /// 框架自带的有 native,nativeModal,inFromLeft,inFromRight,inFromBottom,fadeIn,custom
    static Future jump(BuildContext context, String title) {
        return Application.router.navigateTo(context, title, transition: TransitionType.inFromRight);
        /// 指定了 转场动画
    }

    /// 框架自带的有 native,nativeModal,inFromLeft,inFromRight,inFromBottom,fadeIn,custom
    static Future jumpLeft(BuildContext context, String title) {        return Application.router.navigateTo(context, title, transition: TransitionType.inFromLeft);        /// 指定了 转场动画    }    
    static Future jumpRemove(BuildContext context) {        return Navigator.of(context).pushAndRemoveUntil(            MaterialPageRoute(                builder: (context) => IndexPage(),            ),
            (route) => route == null);    }
    
    /// 自定义 转场动画
    static Future gotransitionCustomDemoPage(BuildContext context, String title) {
        var transition = (BuildContext context, Animation<double> animation,
            Animation<double> secondaryAnimation, Widget child) {
            return new ScaleTransition(
                scale: animation,
                child: new RotationTransition(
                    turns: animation,
                    child: child,
                ),
        };
        return Application.router.navigateTo(context, title, 
                transition: TransitionType.custom,
        /// 指定是自定义动画
        transitionBuilder: transition,

        /// 自定义的动画
        transitionDuration: const Duration(milliseconds: 600));
        /// 时间
    }

    /// 使用 IOS 的 Cupertino 的转场动画,这个是修改了源码的 转场动画
    /// Fluro本身不带,但是 Flutter自带
    static Future gotransitionCupertinoDemoPage(
        BuildContext context, String title) {
        return Application.router.navigateTo(context, title, transition: TransitionType.cupertino);
    }

    // 跳转到主页面IndexPage并删除当前路由
    static void goToHomeRemovePage(BuildContext context) {
        Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(
                builder: (context) => IndexPage(),
        ), (route) => route == null);
    }

    // 跳转到登录页并删除当前路由
    static void goToLoginRemovePage(BuildContext context) {
        Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(
                builder: (context) => Login(),
            ), (route) => route == null);
    }
}

5:接下来基本上路由模块建立完成

需要到main.dart文件夹进行注册一下

import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter_fluro/pages/index_page.dart';
import 'package:flutter_fluro/routers/application.dart';
import 'package:flutter_fluro/routers/routes.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //-----------------路由主要代码start
    final router = Router();
    Routes.configureRoutes(router);
    Application.router = router;
    //-----------------路由主要代码end

    return Container(
      child: MaterialApp(
        title: 'fluro',
        //-----------------路由主要代码start
        onGenerateRoute: Application.router.generator,
        //-----------------路由主要代码end
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          brightness: Brightness.light,
          primaryColor: Color.fromARGB(255, 78, 79, 95),
        ),
        home: IndexPage(),
      ),
    );
  }
}

大功告成,到这里关于flutter采用fluro方式进行的大型项目路由管理就算成功,

使用方法:

NavigatorUtil.jump(context, '/normalPage');
NavigatorUtil.jump(context, '/routingReference?id=200');
NavigatorUtil.goToLoginRemovePage(context);

注意:中文传参问题

NavigatorUtil.jump(context, '/routingReference?id=${Uri.encodeComponent("中文参数")}');

git入门学习

前言

Git(读音为/gɪt/。)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。------ 来自git的基本介绍

说点废话,这里作者只是在用到git的时候,将自己学习到的东西,在这里进行记录,防止后期忘记,哈哈哈

开始

第一步

首先设置一下Git的user name和email, 这里的用户名和邮箱作者理解成了GitHub的用户名和登录邮箱:

$ git config --global user.name "zhengzhuang95"
$ git config --global user.email "[email protected]"

第二步

第二步生成SSH密钥,这里生成SSh是因为git是有SSH加密验签的:

  1. 查看是否先cd C:\Users\Administrator\.ssh文件夹查看一下看是否已经有了ssh密钥,如果没有密钥则不会有此文件夹,有的话就备份删除

  2. 生成密钥:$ssh-keygen -t rsa -C "[email protected]", 最后得到两个文件
    1

    加上原来的一个文件,共3个文件

  3. 添加密钥到ssh: ssh-add id_rsa.pub 输入之前输入密码

  4. 在github上添加ssh密钥,这要添加的是"id_rsa.pub"里面的公钥。
    登录自己的github,进入到https://github.com/settings/keys
    New SSH key
    复制id_rsa.pub里面的内容到Key里,直接 Add SSH key

第三步

开始使用github:

  1. 创建github库
    2

  2. 在本地创建新文件夹,并在文件夹中生成README.md文件,这里主要用于测试上传
    3

  3. 打开Git Bash,其实打开CMD也可以,看着也舒服,这里作者就打开CMD进行操作
    cd到你自己刚才创建的文件夹中,分别执行

    • git init
    • git add README.md
    • git commit -m "first commit"
    • git remote add origin [email protected]:zhengzhuang95/test.git
    • git push -u origin master

    4

第四步

本地仓库修改同步到远程仓库:

git add --all
git commit -m 'second'
git pull origin master
git push origin master

结束语

到这里,最基本的git仓库就算创建成功啦

webpack5 搭建react项目 - 1

前言

在平时工作中,为减少开发成本,一般都会使用脚手架来进行开发,比如 create-react-app。脚手架都会帮我们配置好了 webpack,但如果想自己搭建 webpack 项目要怎么做呢?这边文章将介绍如何使用 webpack 5 来搭建 react 项目,项目地址在文末。

一、简单聊下 Webpacπk

1.1 Webpack 的好处

试想在不使用任何打包工具的情况下,我们很难在项目去使用 es6+ 新语法,TypeScript即使是新的浏览器,也不支持,更别说在项目中使用 ReactVue 了。打包工具能帮我们解决这些问题,打包工具有很多,比如 Webpack、Vite、Snowpack、Rspack 等,这里介绍 Webapck,毕竟生态圈大。

Webpack 是一个 JavaScript 应用程序的静态模块打包工具。 它可以帮我们分析项目结构,将模块打包,最终得以在浏览器中直接使用。 那 Webpack 有哪些好处呢?

开发环境:

  • 新特性&新语法: 像 ESNext 新特性,.less、.ts、tsx/jsx、.vue 等浏览器无法识别的格式文件都能在开发中使用。Webpack 的 Loader 机制能帮助进行转换。
  • 模块化: 在 Webpack 中,一切皆为模块, 我们可以使用模块化编程,把复杂的程序细化为小的模块文件。
  • 模块热替换(HMR): 提供模块热替换功能, 在修改代码后,不需要重新加载整个页面,只需要替换修改的模块,从而提高开发效率。
  • Source Map: 提供了 Source Map 功能,可以将编译后的代码映射回原始源代码,从而方便我们进行调试。

生产环境:

  • 性能优化:可以压缩代码,合并文件,从而减少网络请求。
  • 代码分割:可以进行代码分割,实现按需加载或者并行加载,从而减少页面加载时间,提高用户体验。
  • 缓存优化:可以根据文件内容生成 hash 值,从而实现缓存优化,减少网络请求和服务器负载。

1.2 Webpack 的基本概念

这里我们先简单熟悉下 Webpack 基本概念,下面搭建项目时都要用到。

  • entry: 使用哪个模块来作为构建的起始入口。
  • output: 最终打包后的文件放在哪里,以及如何命名这些文件。
  • loader: 是处理文件的转换器,用于对模块源码进行转换,webpack 只能识别 js、json 文件,像 css 、ts 、jsx等文件都需要通过 loader 进行转换。
  • plugin: 是一种可扩展的机制,可以打包过程中添加额外的功能。比如打包优化,资源管理,注入环境变量等。
  • mode: 对于不同的环境,我们往往需要不同的配置,通过设置 mode 参数来选择环境。

二、搭建 React 项目

上面简单介绍了 webpack,接下来开始搭建我们的项目。

2.1 项目初始化

我们使用 pnpm 来初始化一个项目(8.x 版本需要 node 在 16 + ),为什么选用 pnpm ,可以看下包管理工具 —— 更推荐的 pnpm

mkdir create-react 
cd create-react 
pnpm init --y 
git init

2.2 安装配置 react & TypeScript

引入 reactreact-dom 和对应的类型包 @types/react 、@types/react-dom。这里使用的版本是18.2.0。

pnpm add react react-dom
pnpm add -D @types/react @types/react-dom

然后配置 TypeScript

pnpm add typescript -D

有了 TypeScript,就可以直接通过 tsc 命令生成一个 tsconfig.json 的配置文件。

tsc --init

可以按照所需手动修改 ts 的配置文件。

{
  "compilerOptions": {
    "target": "ESNext",                                                                        
    "jsx": "preserve", 
    "module": "ESNext",                                                
    "moduleResolution": "node",
    "rootDir": "./src",                     
    "baseUrl": ".",                                  
    "paths": {
      "common/*": [
        "src/common/*"
      ],
      "@/*": [
        "src/*"
      ]
    },      
    "strict": true,                                 
    "sourceMap": true,
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "importHelpers": true,
    "noUnusedLocals": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedParameters": true,
    "noEmit": true,
    "skipLibCheck": true                        
  },
  "include": ["src"]
}

接着我们创建 src 目录,在根目录创建 index.tsx,在 src 下创建 App.tsx 。

// index.tsx
import * as React from 'react'
import * as ReactDOM from 'react-dom/client'

import App from './src/App'

const root = ReactDOM.createRoot(document.getElementById('app')!)
// v18 的新方法
root.render(<App />)

// App.tsx
import * as React from 'react'

const App: React.FC = () => {
  return <div>hello 小柒</div>
}

export default App

前置准备已经做好, 接下来我们来一步一步的使用 webpack 打包 React 项目。

2.3 Webpack 相关

(1) 安装 Webpack

  • webpack 、webpack-cli :打包必备。
  • webpack-dev-server: 一个提供热更新的开发服务器,对开发阶段友好。
  • webpack-merge: 用来合并配置文件。
pnpm add webpack webpack-cli webpack-dev-server webpack-merge -D

(2) 配置 Webpack 文件

Webpack 默认读取的是 webpack.config.js 文件,但在实际开发中我们需要将生产环境和开发环境分开。我们先来整理下配置文件的目录结构,在 scripts 目录下创建三个配置文件。

image.png

修改下 package.json 中的 scripts 配置,用来简化命令。

"scripts": {
    "dev": "cross-env NODE_ENV=development webpack serve -c scripts/webpack.dev.js",
    "build": "cross-env NODE_ENV=production webpack -c scripts/webpack.prod.js"
  },

我们使用 NODE_ENV = production 来设置环境变量,为了在不同的平台上都能使用,我们使用 cross-env 来兼容,这样在不同环境下也能正确获取环境变量。

pnpm add cross-env -D

我们将一些通用的配置写在 webpack.base.js 文件里。

const path = require('path')

module.exports = {
  entry: path.resolve(__dirname, '../src/index.tsx'),
  output: {
    path: path.resolve(__dirname, '../dist'), // 打包后的代码放在dist目录下
    filename: '[name].[hash:8].js', // 打包的文件名
  },
}

webpack.dev.js 文件和 webpack.prod.js 中引入通用配置。

// webpack.dev.js
const { merge } = require('webpack-merge')
const base = require('./webpack.base.js')

module.exports = merge(base, {
  mode: 'development', // 开发模式
  devServer: {
	  open: true, // 编译完自动打开浏览器
    port: 8080,
  },
})

// webpack.prod.js
const { merge } = require('webpack-merge')
const base = require('./webpack.base.js')

module.exports = merge(base, {
  mode: 'producton', // 生产模式
})

到这里环境基本搭建好了,接下来我们就一步一步的来完善配置。

(3) 配置 babel

由于 webpack 只能识别js、json 文件, 无法识别 jsx/tsx 文件,此时如果我们尝试启动项目肯定会报错。如何让 webpack 能识别呢?此时我们就需要使用 babel-loader 来转换代码,babel-loader 可以让 webpack 在构建的时候借助 Babel 对JS代码进行转译。


注意💡: Babel 是一个 JavaScript 编译器。主要用于将高版本的JavaScript代码转为向后兼容的JS代码,从而能让我们的代码运行在更低版本的浏览器或者其他的环境中。


babel-loader 的转码功能依赖 Babel 的核心转码包 @babel/core,如果要转义 React 文件还需要引入 @babel/preset-react 这个预设; 对于 ts 我们除了可以使用 ts-loader 外,也可以使用 @babel-preset-typescript 来编译 ts 代码;在实际项目中,考虑到浏览器的兼容性问题,我们都会设置目标浏览器来转换我们的代码,这时候就需要使用到 @babel/preset-env 这个预设。这里就不过多的介绍 babel 配置 ,接下来我们来安装上述提到的关于 babel 的依赖包并进行 webpack 的配置。

pnpm add -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript

我们在 webpack.base.js 文件添加下面配置,我们将 js|ts、jsx|tsx 文件都交给 babel-loader 来处理,并配置对应的 presets,这些 presets 会从右向左执行。

{
... 
resolve: {
	// 配置 extensions 来告诉 webpack 在没有书写后缀时,以什么样的顺序去寻找文件
  extensions: ['.mjs','.js', '.json', '.jsx', '.ts', '.tsx'], // 如果项目中只有 tsx 或 ts 可以将其写在最前面
},
module: {
    rules: [
      {
        test: /.(jsx?)|(tsx?)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  targets: 'iOS 9, Android 4.4, last 2 versions, > 0.2%, not dead', // 根据项目去配置
                  useBuiltIns: 'usage', // 会根据配置的目标环境找出需要的polyfill进行部分引入
                  corejs: 3, // 使用 core-js@3 版本
                },
              ],
              ['@babel/preset-typescript'],
              ['@babel/preset-react'],
            ],
          },
        },
      },
    ],
  },
...
}

运行 pnpm run build,打包后会生成 dist 目录,可以看到打包后的 js 文件。

image.png 此时如果想要在浏览器中访问,我们需要手动在 dist 目录下添加 html 文件,并引入打包好的 js 文件:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
	<script defer src="main.7a68ecf3.js"></script>
</head>
<body>
  <div id="app"></div>
</body>
</html>

在浏览器中打开 html 文件,即可访问。

image.png

如果想项目启动或打包时自动生成 html 文件 ,要怎么做呢?我们可以借助 html-webpack-plugin 插件来帮忙自动生成 html文件,先在根目录创建一个模板 index.html 文件。

<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, user-scalable=no, minimum-scale=1, maximum-scale=1, minimal-ui, viewport-fit=cover"
    />
    <title></title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

安装 html-webpack-plugin

pnpm add -D html-webpack-plugin

webpack.base.js 文件中添加以下配置:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  // ...
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../index.html'), // 使用自定义模板
    }),
  ],
  // ...
}

pnpm run build一下,dist 目录下已经自动生成了 index.html 文件,并引入了打包的 js 文件。

image.png

pnpm run dev 启动开发时,我们也能在 localhost:8080 中看到页面了。


注意💡:在使用 dev-server 启动时,它会读取 Webpack 的配置文件(默认是 webpack.config.js),然后将文件打包到内存中(我们看不到 dist 文件夹的生成,Webpack 会打包到硬盘上),用默认地址打开时默认显示index.html 的内容,如果没有index.html 文件,则显示目录。


(4) css 配置

项目中样式的引用那是必不可少的,这里使用 less 来语法来举例。在 src下创建 index.less 文件,在 App.tsx 中引入。此时启动项目,控制台一定会报错。

// index.less
@color: red;

.wrapper {
  display: flex;
  color: @color;
} 

// App.tsx
import * as React from 'react'
import './index.less'

const App: React.FC = () => {
  return <div className="wrapper">hello 小柒</div>
}

export default App

less 文件可以使用 less-loader 将 less 编译为 css,一般情况下我们还会使用 Postcss 来处理 CSS,在 Webpack 中我们可以使用 postcss-loader 来处理 css。


注意💡PostCSS 本身是一个工具,有了它我们可以使用 JavaScript 代码来处理 CSS。它将 CSS 解析成抽象语法树 AST, 将 AST 交给插件来处理并得到结果。PostCSS 的插件体系很强大,提供很多插件,比如:autoprefixer 用来添加浏览器前缀、 cssnano 用来压缩 CSS、 postcss-preset-env 用来根据目标浏览器生成 CSS的 polyfill等等。当然我们也可以实现自己的 PostCSS 插件。


处理过的 css 可以使用 css-loader 来解析成 js ,我们来看看 css-loader 解析之后的内容是什么。

image.png

打印出来是一个数组,第二个元素是我们想要的 css 样式。

image.png

css-loader 只能帮我们将 css 解析成 js,但不能挂载到元素上。如果想让 css 生效,我们要手动挂载。

image.png

这样就达到了我们想要的效果,不过这么写未免有点憨憨。

image.png

想要自动挂载样式,style-loader 可以帮我们实现,它负责将 css 样式通过 style 标签插入到 DOM 中。下面是通过 style-loader 实现样式挂载,自动添加 style 标签到head 中。

image.png

通过上述,可以来配置我们的 webpack.dev.js 文件了。第一步还是先安装所需要的依赖包。

// less-loader 默认是11版本过高会报错。
// 两种方法:1、要么指定低版本的 less-loader@^6.2.0  2、同时安装 less 和 postcss
pnpm add -D style-loader css-loader  postcss-loader  less-loader@^6.2.0 postcss-preset-env

// 或者
pnpm add -D style-loader css-loader postcss postcss-loader less less-loader postcss-preset-env

第二步配置 webpack.dev.js 文件。这样我们就可以在代码中正常使用 less 啦~。

// webpack.dev.js
module: {
    rules: [
      // ...
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {		
              postcssOptions: {
                [['postcss-preset-env', {}]]
              },
            },
          },
          'less-loader',
        ],
				// 排除 node_modules 目录
        exclude: /node_modules/,
      },
    ],
  },

我们可以发现,css 样式都打包到最终中的 js 文件了,如果项目比较复杂,css 都打包在js文件,js的体积就会越来越大。在生产环境下,我们肯定希望打包出来的文件体积越小越好,在生产环境下,我们一般是用 MiniCssExtractPlugin 代替 style-loader,来将打包后的 js 文件的css提取出来,单独创建一个 css 文件,使用 link 的方式引入。除了分离 css文件减小 js 体积, 还可以使用 CssMinimizerWebpackPlugin 优化、压缩来 CSS 体积。 看看 webpack.prod.js 文件中的配置:

// webpack.prod.js
// ...
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = merge(base, {
  // ...
  module: {
    rules: [
      {
        test: /\.(css|less)$/,
        use: [
          MiniCssExtractPlugin.loader, // 使用 MiniCssExtractPlugin.loader 代替 style-loader
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              // 它可以帮助我们将一些现代的 CSS 特性,转成大多数浏览器认识的 CSS,并且会根据目标浏览器或运行时环境添加所需的 polyfill;
              // 也包括会自动帮助我们添加 autoprefixer
              postcssOptions: {
                plugins: [['postcss-preset-env', {}]],
              },
            },
          },
          'less-loader',
        ],
        // 排除 node_modules 目录
        exclude: /node_modules/,
      },
    ],
  },
optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
      // `...`,
      new CssMinimizerPlugin({
        // 默认开启
        // parallel true:  // 多进程并发执行,提升构建速度 。 运行时默认的并发数:os.cpus().length - 1
      }),
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'assets/css/[hash:8].css', // 将css单独提测出来放在assets/css 下
    }),
  ],
})

打包后的效果如下:

image.png

(5) 图片&字体

先来看看图片的配置,创建文件夹 assets/images,引入图片 coffee.jpg。

image.png

我们在 App.tsx 中引入张图,这里使用 @ 符号来声明路径,需要在 base 文件中进行alias 属性的配置,同时还要对 ts 类型声明进行声明,否则 ts 类型会报错。

image.png

此时再编译,会报错,webpack 无法识别图片,需要使用loader 去解析图片资源。

image.png

对于图片的处理,在 webpack 5 之前,我们可以使用 file-loaderurl-loader ,这两个 loader 都可以帮我们解析图片资源。


注意💡

  • file-loader :不仅仅可以处理图片资源,本质是处理文件导入地址并替换成其访问地址,并把文件输出到相应位置,音视频等资源也可以使用它。
  • url-loader:file-loader 的升级版,包含 file-loader 的全部功能,并且能够根据配置将符合配置的文件转换成 Base64 方式引入,将小体积的图片 Base64 引入项目可以减少 http 请求,也是一个前端常用的优化方式。

我们先来看看 webpack 5 之前如何配置。先使用 file-loader 来处理图片资源,可以看到图片是一个可访问的地址。

image.png

再使用url-loader 看看效果,在不设置 limit 限制时,会转换成 Base64 格式引入。

image.png

当我们配置了 limit 时(这里设置比较小,项目中应合理配置),图片超过这个限制就会使用file-loader去处理图片,表现如上。一般情况下我们使用url-loader来处理。在webpack.base.js中配置:

// webpack.base.js
resolve: {
   //...
  alias: {
    '@': path.resolve(__dirname, '../src'),
  },
},
module: {
	rules: [
		//...
		{
        test: /\.(png|jpe?g|gif|svg|webp)$/i,
        use: [
					// {
	        //   loader: 'file-loader',
          // },
          {
            loader: 'url-loader',
            options: {
              limit: 2000,
              // //限制打包图片的大小:
              // //如果大于或等于2000Byte,则按照相应的文件名和路径打包图片;如果小于2000Byte,则将图片转成base64格式的字符串。
              // name: 'img/[name].[hash:8].[ext]',
              // //img:图片打包的文件夹;
              // //[name].[ext]:设定图片按照本来的文件名和扩展名打包,不用进行额外编码
              // //[hash:8]:一个项目中如果两个文件夹中的图片重名,打包图片就会被覆盖,加上hash值的前八位作为图片名,可以避免重名。
            },
          },
        ],
      },
	]
}

了解图片的配置方式后,我们同样可以使用 url-loader 去处理字体。一般数字类型都用din,这里我们引入一个ttf字体,使用@font-face 来定义字体名。

image.png

接着在 webpack.base.js 文件中配置下。

// webpack.base.js
module: {
	rules: [
    // ...
		{
	       test: /\.(eot|ttf|woff|woff2)$/i,
	       use: [
	          {
	            loader: 'url-loader',
	          },
	        ],
		}
	]
}

这样我们就能使用 din 字体了,编译运行,字体生效~。

image.png

Webpack 5 中的 asset module 其实已经帮我们处理了,可以直接使用。资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。

image.png

这里我们使用 asset 类型,并配置 parser.dataUrlCondition.maxSize 属性,小于 maxSize 的会被打包成 base64,否则会被打包到目录,以url的形式引入。话不多说直接上配置。

// webpack.base.js
module: {
	rules: [
	    // ...
		{
	       test: /\.(eot|ttf|woff|woff2)$/i,
	       use: [
	          {
	            loader: 'url-loader',
	          },
	        ],
		}
	]
}

build 一下,图片和字体都被分别打包再 imgs 和 fonts下了。

image.png

Flutter 常用库及时使用入门级方法(一些经常用到的)

UI相关

flutter_screenutil

flutter_screenutil: ^0.6.0

https://pub.flutter-io.cn/packages/flutter_screenutil

flutter屏幕适应方案,让你的UI在不同尺寸的屏幕上能够显示合理的布局!

使用方法(入门): https://pub.flutter-io.cn/packages/flutter_screenutil

flutter_swiper

flutter_swiper: ^1.1.6

https://pub.flutter-io.cn/packages/flutter_swiper

flutter最强大的siwiper, 多种布局方式,无限轮播,Android和IOS双端适配!

使用方法(入门): https://pub.flutter-io.cn/packages/flutter_swiper

fluttertoast

fluttertoast: ^3.1.3

https://pub.flutter-io.cn/packages/fluttertoast

用于Android和ios的toast库!

使用方法(入门): https://pub.flutter-io.cn/packages/fluttertoast

azlistview

azlistview: ^0.1.2

https://pub.flutter-io.cn/packages/fluttertoast

城市选择器!

使用方法(入门): https://pub.flutter-io.cn/packages/fluttertoast

flutter_datetime_picker

flutter_datetime_picker: ^1.2.6

https://pub.flutter-io.cn/packages/flutter_datetime_picker

日期选着三级联动!

使用方法(入门): https://pub.flutter-io.cn/packages/flutter_datetime_picker

pin_input_text_field

pin_input_text_field: ^2.0.1

https://pub.flutter-io.cn/packages/pin_input_text_field

Flutter平台上用来展示不同样式的验证码UI!

使用方法(入门): https://pub.flutter-io.cn/packages/pin_input_text_field

网络请求

dio

dio: ^3.0.3

https://pub.flutter-io.cn/packages/dio

dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配器等!

使用方法(入门): https://pub.flutter-io.cn/packages/dio

Flutter创建插件详解并发布到Pub库

Flutter创建插件详解并发布到Pub库

创建Flutter Plugin插件项目

(1)使用Android Studio创建项目

image

(2)使用flutter create命令行创建

flutter create --org com.awei --template=plugin -a java --description "A Flutter plugin for using devices informations in Android" flutter_device_information

常用的命令参数如下:

  • --org:定义项目的组织结构
  • -a:用什么语言编写Android代码
  • --description:插件的描述
  • -i:用什么语言编写iOS代码

上面那个命令的意思是:创建一个插件,包名为“com.awei”,指定Android代码使用Java语言编写,插件项目名称为“flutter_device_information”,项目描述为:“A Flutter plugin for using devices informations in Android”。
6098829-378c8ff66e6b945d

到这里项目创建完成,接下来就是进行项目插件的开发工作,这里就不做进行详细的介绍,等项目创建完成之后接下来就是上传到github仓库中

到这里其实自己写的插件是可以用的,使用方法在pubspec.yaml文件中直接写入

dependencies:
  rain:
    git: https://github.com/zhengzhuang96/flutter_eui.git

将项目发布到pub中

带项目编写完成并无bug的时候,这个时候可以上传到pub中使用,这个过程中首先保证你的终端可以翻墙,然后还有一个谷歌邮箱账号

先在根目录文件pubspec.yaml中顶部写入自己插件的信息

name: rain
description: 轻量、可靠的移动端 Flutter 组件库
version: 0.0.1
homepage: https://github.com/zhengzhuang96/rain.git

编写好之后根目录下运行命令,进行发布

flutter packages pub publish --server=https://pub.dartlang.org

运行之后显示Look greate! Are you ready to upload your package(y/n)?证明并无问题是否发布,输入y
image-20200331145358750

它会让你去进行账号授权,复制它给你的连接放到浏览器中进行授权,这里就需要翻墙了,授权成功出现下面的结果就证明成功,然后等待上传
image-20200331145619616

等待上传会很慢,这里要是一只卡住,说明你的终端没有翻墙成功

image-20200331145609390

等一切上传之后出现Successfully uploaded package.证明上传成功
image-20200331163516059

当你上传成功之后,在https://pub.flutter-io.cn/中不能瞬间出现的,需要大约等20分钟时到1小时左右,才能搜索到,其实上传成功之后就不用等待了,直接可以在项目中使用

dependencies:
  rain:
    git: 0.0.1

大功告成!!!

mac brew 安装mysql

打开控制台

$ brew install mysql

image

  1. 我们现在已经配置成功了,需要设置根密码,它让我们输入mysql_secure_installation
$ mysql_secure_installation

image

结果输入密码后报错:Error: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

解决方法:先执行mysql.server start重启一下,然后mysql_secure_installation,在输入密码基本上就成功了

然后会有很多问题,来让你回复,

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
同意呢就回复y,不同意就回复其他的,比如a呀b呀c呀
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.
默认情况下,MySQL安装有一个匿名用户,
允许任何人登录MySQL而不必
为他们创建的用户帐户。这只是为了
测试,使安装更顺利。
你应该在投入生产前把它们去掉环境。

这样的就是看你自己的意愿了

Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.
通常,根目录只允许从
“本地主机”。这保证了有人不能猜到
来自网络的根密码。
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.
重新加载特权表将确保所有更改
到目前为止所做的将立即生效。
  1. 然后前往下载,mac navicat免激活版
    第一步:控制台执行
    sudo spctl --master-disable
    第二步:下载安装即可使用,里面还有一个汉化包
链接:https://pan.baidu.com/s/1LJAXn13KBcb4Xq8xfVXlhw  密码:ra1k

第三步:汉化
复制中文包”zh-Hans.lproj”放到 /Contents/Resources 即可。(应用程序右键显示包内容)
image
image
image
到这里就安装完成了,
image
完了点好。如果出现连接错误:
打开终端,通过终端连接mysql数据库时候我们会看到这样的信息:

1045 - Access denied for user 'root'@'localhost' (using password: YES)

不要慌,正常,解决上面错误的方法之一就是重新设置我们的mysql的root密码
第一,右击选择这条数据库,选择编辑连接
第二,在常规里面重新编辑密码即可

到这一步就大功告成
image

Taro,快速上手教程(一)

前言

最近公司Boss准备开发几款可以在微信小程序端和H5端同时运行的一套商城,接着就是任务下发喽,但是有一点,时间紧任务重,Boss直接说其他的不管,反正几个星期之内必须上线,~~~头疼。那就只好想办法喽

机缘巧合在一个博客栏目看到了Taro的beta版本,研究下,心里小九九就像看一下,谁知道是啥呢,这不看不知道一看吓一跳,先上个图

3173362987-5bcdca4b156c7_articlex

这简直是一个神器啊,基本上等于自己多了这么多技能,感谢创作者们的激情付出

介绍

Taro是一套遵循 React 语法规范的多端统一开发框架

多端统一开发框架,支持用 React 的开发方式编写一次代码,生成能运行在微信小程序、H5、React Native 等的应用。

Taro 是一套遵循 React 语法规范的 多端开发 解决方案。现如今市面上端的形态多种多样,Web、React-Native、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。

使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信小程序、H5、RN 等)运行的代码

官网:https://taro.aotu.io/

React 语法风格

Taro 遵循 React 语法规范,它采用与 React 一致的组件化**,组件生命周期与 React 保持一致,同时支持使用 JSX 语法,让代码具有更丰富的表现力,使用 Taro 进行开发可以获得和 React 一致的开发体验。

其实说实话,就算不会React,跟着Taro学习,看几遍也就会了,作者就这这样学习的,嘻嘻

正言

废话不多说,直接上,正所谓,算了忘了古诗词了,接下来进入Taro的世界吧

安装

先来安装一下Taro吧

/** Quick Start With NPM Or Yarn **/
$ npm install -g @tarojs/cli
$ yarn global add @tarojs/cli

小伙伴们安装成功了吗,如果不出现什么意外的情况下,基本上安装都能成功,不成功的小伙伴看一下自己的node哦,node没错的话,可能是网络的原因,可以尝试一下cnpm吧

安装成功后基本上可以看到以下画面

2

看到这里证明你安装成功了哦!下接下来输入

taro -V

3

看一下版本哦,目前Taro可能处于初期开发阶段,版本更新会比较快,不过不要紧,不会影响到你的项目哦,相反会更好

好了安装成功后,Taro就可以正常使用啦

创建项目

接下来创建项目就是喽

Taro init demo

taro会以非常快速度创建完成
4

这里作者不知道为啥地下有点不好,但不要紧,无关大雅

5

当你看到这里时,Taro项目就创建成功喽,我感觉作者还是比较皮的,还有个可爱的小表情😊

Taro目录

好了,看一下Taro目录喽
6

具体Taro使用命令看一下项目的package.json目录哦

先来运行一下吧,输入

npm run dev:h5

浏览器会自动打开一个10086端口的地址
7

Taro项目就创建成功啦,简单吧,他的开发其实也挺简单哦,快去上手吧

Taro介绍结尾,运行

微信小程序
选择微信小程序模式,需要自行下载并打开微信开发者工具,然后选择项目根目录进行预览。
微信小程序编译预览及打包

# npm script
$ npm run dev:weapp
$ npm run build:weapp

H5
H5 模式,无需特定的开发者工具,在执行完下述命令之后即可通过浏览器进行预览
H5 编译预览及打包

# npm script
$ npm run dev:h5

React Native
React Native 端运行需执行如下命令,React Native 端相关的运行说明请参见 React Native 教程

# npm script
$ npm run dev:rn

百度小程序
选择百度小程序模式,需要自行下载并打开百度开发者工具,然后在项目编译完后选择项目根目录下 dist 目录进行预览。
百度小程序编译预览及打包

# npm script
$ npm run dev:swan
$ npm run build:swan

支付宝小程序
选择支付宝小程序模式,需要自行下载并打开支付宝小程序开发者工具,然后在项目编译完后选择项目根目录下 dist 目录进行预览。
支付宝小程序编译预览及打包

# npm script
$ npm run dev:alipay
$ npm run build:alipay

对了,Taro更新比较快,还要记得更新Taro项目哦

Taro 提供了更新命令来更新 CLI 工具自身和项目中 Taro 相关的依赖
更新 Taro CLI 工具

# taro
$ taro update self
# npm
npm i -g @tarojs/cli@latest
# yarn
yarn global add @tarojs/cli@latest

安装成功喽,看下一篇文章看Taro开的的第一个项目

JS 判断PC、android、ios、微信浏览器

通过js userAgent来判断

判断访问此链接的操作系统

var Agents = new Array("Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod");
var flag = true;

/**
 * 初始化加载程序
 */
window.onload = function(){
    console.log(isMobile());
    console.log(isWechat());
    console.log(getOsVersion());
}

/**
 * 判断是不是移动端
 * @returns {boolean}
 */
function isMobile() {
    var userAgentInfo = navigator.userAgent;
    for (var v = 0; v < Agents.length; v++) {
        if (userAgentInfo.indexOf(Agents[v]) > 0) {
            flag = false;
            break;
        }
    }
    document.write("是否移动端-"+ !flag+"//");
    return "是否移动端-" + !flag;
}

/**
 * 判断是不是微信浏览器
 * @returns {boolean}
 */
function isWechat() {
    var ua = navigator.userAgent.toLowerCase();

    if(ua.match(/MicroMessenger/i)=="micromessenger"){
        document.write("是微信浏览器//");
        return "是微信浏览器";
    }
    else{
        document.write("不是微信浏览器//");
        return "不是微信浏览器";
    }
}

/**
 * 判断浏览器所在机器操作系统版本
 */
function getOsVersion(){
    var u = navigator.userAgent,version = '';
    if (u.indexOf('Mac OS X') > -1) {
        //ios
        var regStr_saf = /OS [\d._]*/gi;
        var verinfo = u.match(regStr_saf);
        version ="ios" + (verinfo + "").replace(/[^0-9|_.]/ig,'').replace(/_/ig,'.');
        document.write("ios");
    } else if (u.indexOf('Android') > -1
        || u.indexOf('Linux') > -1) {
        //android
        version ="android" + u.substr(u.indexOf('Android') + 8, u.indexOf(";", u.indexOf("Android")) - u.indexOf('Android') - 8);
        document.write("android");
    } else if (u.indexOf('BB10') > -1) {
        //黑莓bb10系统
        version ="黑莓bb10系统" +  u.substr(u.indexOf('BB10') + 5, u.indexOf(";", u.indexOf("BB10")) - u.indexOf('BB10') - 5);
        document.write("黑莓bb10系统");
    } else if (u.indexOf('IEMobile')) {
        //windows phone
        version ="windows phone";
        document.write("windows phone")
    }
    return version;
}

JavaScript数组去重

数组去重

Array类型并没有提供去重复的方法,如果要把数组的重复元素干掉,那得自己想办法:

方法一:ES6方法:

var arr=[2,3,5,4,5,2,2,'5'];
var s=new Set();
arr.map((item,index)=>{
	s.add(item)
})
var temp=[];
for(var i of s){
	temp.push(i)
}
console.log(temp)

得到结果 [ 2, 3, 5, 4, '5' ]方法很简单,不得不说es6是大势所趋啊,也希望各大浏览器厂商赶紧支持起来!

方法二:利用indexOf方法;

var aa=[1,3,5,4,3,3,1,4]
function arr(arr) {
    var result=[]
    for(var i=0; i<arr.length; i++){
        if(result.indexOf(arr[i])==-1){
            result.push(arr[i])
        }
    }
    console.log(result)
}            
arr(aa)

方法三:

function unique(arr) {
    var result = [], isRepeated;
    for (var i = 0, len = arr.length; i < len; i++) {
        isRepeated = false;
        for (var j = 0, len = result.length; j < len; j++) {
            if (arr[i] == result[j]) {   
                isRepeated = true;
                break;
            }
        }
        if (!isRepeated) {
            result.push(arr[i]);
        }
    }
    return result;
}

方法四:

总体思路是把数组元素逐个搬运到另一个数组,搬运的过程中检查这个元素是否有重复,如果有就直接丢掉。从嵌套循环就可以看出,这种方法效率极低。我们可以用一个hashtable的结构记录已有的元素,这样就可以避免内层循环。恰好,在Javascript中实现hashtable是极为简单的,改进如下:

function unique(arr) {
    var result = [], hash = {};
    for (var i = 0, elem; (elem = arr[i]) != null; i++) {
        if (!hash[elem]) {
            result.push(elem);
            hash[elem] = true;
        }
    }
    return result;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.