程序_程序员 - CSDN
精华内容
参与话题
  • 什么是程序

    千次阅读 2018-01-21 16:32:04
    程序是为了实现一个特定的目标而设计的一组可操作的工作步骤,对于计算机而言,程序就是系统可以识别的一组有序的指令。程序能指挥计算机执行我们想要它做的动作。程序储存在磁盘上,在执行时从磁盘到内存再到寄存器...
    

     首先,程序是什么呢?程序是为了实现一个特定的目标而设计的一组可操作的工作步骤,对于计算机而言,程序就是系统可以识别的一组有序的指令。程序能指挥计算机执行我们想要它做的动作。程序储存在磁盘上,在执行时从磁盘到内存再到寄存器,最后被CPU执行,程序的执行过程与古代皇上的处理政务过程有些类似,可以进行类比。在古代,皇宫外部的民情、大臣写的奏折就好比程序,外面的天下就好比硬盘,程序储存在硬盘中,大臣好比内存,大臣将民情总结并上交给太监,而太监就是寄存器,太监将奏折上交给皇上,让皇上处理,而CPU也是从寄存器中取出程序,然后执行。程序是与计算机沟通的语言,由特定语法和关键字构成,从入口点开始,原则是由上而下,从左往右,一行一行执行的。

         接着,程序设计语言又有那些呢?在计算机最初诞生的时候,程序是一段一段的二进制语言,称为机器语言。由于二进制语言的编程实在是不方便,不适合编写、阅读,于是慢慢有了汇编语言,汇编语言就是将机器语言中的一些关键的指令用一些符号来代替,与机器语言相比,汇编确实有了一些可读性,但是汇编还是很复杂,编程的工作量还是很大。于是高级语言应运而生,高级语言离机器越来越远,相反,语法接近人类的自然语言,而且,高级语言执行的不再是指令,而是语句,一行语句对应多个指令,因此,它的开发效率越来越高。但是,高级语言必须编译成机器码。高级语言具有良好的可移植性。

     关于程序有几个基本概念。编译型语言指需要先经过编译和链接程序产生可执行文件的语言,比Java/c/c++等。解释型语言指不需要编译和链接的过程,直接在特定的程序或环境下即可执行的语言,如JavaScript/python等。数据是计算机程序处理的对象,可以是整数、实数、字符、也可以是图像、声音等的编码表示。数据结构指数据与数据间存在一种或多种特定关系,与数据结构密切相关的便是数据的类型和数据的存放。程序设计就是编程的过程。软件是程序与文档共同组成。

    展开全文
  • 50个小程序源码

    2020-07-30 23:31:54
    租赁行业、装修装饰、智能家居、招聘行业、医疗保健、演绎博览、新闻资讯、小游戏类、小工具类小程序源码,
  • 这是我为自己写的一款表白的程序,并且己用它表白成功,于是几经努力把它完成为一个完整的程序,这是我准备完成的程序之爱系列第一辑,希望能多做几辑吧。
  • 一个源程序到一个可执行程序的过程:预编译、编译、汇编、链接。 其中,编译是主要部分,其中又分为六个部分:词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化。 链接中,分为静态链接和动态链接...




    一个源程序到一个可执行程序的过程:预编译、编译、汇编、链接。
    其中,编译是主要部分,其中又分为六个部分:词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化。
    链接中,分为静态链接和动态链接,本文主要是静态链接。

    一、预编译:主要处理源代码文件中的以“#”开头的预编译指令。处理规则见下
    1.删除所有的#define,展开所有的宏定义。
    2.处理所有的条件预编译指令,如“#if”、“#endif”、“#ifdef”、“#elif”和“#else”。
    3.处理“#include”预编译指令,将文件内容替换到它的位置,这个过程是递归进行的,文件中包含其他文件。
    4.删除所有的注释,“//”和“/**/”。
    5.保留所有的#pragma 编译器指令,编译器需要用到他们,如:#pragma once 是为了防止有文件被重复引用。
    6.添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告是能够显示行号。

    C语言的宏替换和文件包含的工作,不归入编译器的范围,而是交给独立的预处理器。
    C语言中源代码文件的文件扩展名为.c,头文件的文件扩展名为.h,经预编译之后,生成xxx.i文件。
    在C++,源代码文件的扩展名是.cpp或.cxx,头文件的文件扩展名为.hpp,经预编译之后,生成xxx.ii文件。

    二、编译:把预编译之后生成的xxx.i或xxx.ii文件,进行一系列词法分析、语法分析、语义分析及优化后,生成相应的汇编代码文件。

    (结合程序来说明编译的几个步骤)
    有C语言的源代码如下:
    arr[3] = (a+4)*(3+8);

    1.词法分析:利用类似于“有限状态机”的算法,将源代码程序输入到扫描机中,将其中的字符序列分割成一系列的记号
    以上的一行C语言程序,一共有16个空字符,经扫描机扫描之后,产生了16个记号。lex可以实现词法分析。见下表:

    这里写图片描述

    见上图:
    词法分析产生的记号分类有:关键字、标识符、字面量(数字、字符串)、特殊符号(加号、等号等)

    2.语法分析:语法分析器对由扫描器产生的记号,进行语法分析,产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树。上述的代码就是
    各种表达式的组合:赋值表达式、加法表达式、乘法表达式、数组表达式和括号表达式组成的复杂表达式。yacc可以实现语法分析,根据用户给定的规则(不同的编程语言对应不同的语法规则)对记号表进行解析。

    这里写图片描述

    见上图:
    整个语句被看作是一个“赋值表达式”,“=”左边是一个“数组表达式”,右边是一个“乘法表达式”。数组表达式又由两个符号表达式组成,符号表达式就是最小的表达式,之后同理。

    在语法分析的同时,就把运算符的优先级确定了下来,如果出现表达式不合法,——各种括号不匹配、表达式中缺少操作,编译器就会报错。

    3.语义分析:语法分析器只是完成了对表达式语法层面的分析,语义分析器则对表达式是否有意义进行判断,其分析的语义是静态语义——在编译期能分期的语义,相对应的动态语义是在运行期才能确定的语义。
    其中,静态语义通常包括:声明和类型的匹配,类型的转换,那么语义分析就会对这些方面进行检查,例如将一个int型赋值给int*型时,语义分析程序会发现这个类型不匹配,编译器就会报错。

    经过语义分析阶段之后,所有的符号都被标识了类型(如果有些类型需要做隐式转化,语义分析程序会在语法树中插入相应的转换节点),见下图:

    这里写图片描述
    这个语句中的类型都是int型,无须做转换。

    4.优化:*源代码级别的一个优化过程*,例如该语句中的(3+8)的值可以在编译期确定,源代码优化器会将整个语法树转换成中间代码——语法树的顺序表示,十分接近目标代码。
    中间代码有很多种类型,最常见的是“三地址码”和“P-代码”,其中三地址码的基本形式为:x = y op z,表示将变量y和z进行op操作后,赋值给x,op操作可以是加减乘除等。
    经优化之后的语法树为:

    这里写图片描述

    该语句的三地址码:
    t1 = 3 + 8;
    t2 = a + 4;
    t3 = t2 * t1;
    arr[3] = t3;

    t1由数字11代替,省去t3,经优化或的三地址码为:
    t2 = a +4;
    t2 = t2 + 11;
    arr[3] = t2;

    另一个关于中间代码的要点:中间代码使得编译器可以被分成前端和后端,编译器前端负责产生与机器无关的中间代码,编译器后端将中间代码转换为机器代码。
    源代码优化去产生中间代码标志着下面的过程都属于编译器后端,后端主要包括:代码生成器和目标代码优化器。

    5.目标代码生成:由代码生成器将中间代码转换成目标机器代码,生成一系列的代码序列——汇编语言表示。

    6.目标代码优化:目标代码优化器对上述的目标机器代码进行优化:寻找合适的寻址方式、使用位移来替代乘法运算、删除多余的指令等。

    上述的六个步骤完毕之后,编译过程也就告一段落了。最终产生了由汇编语言编写的目标代码

    gcc把预编译和编译两个步骤合并成一个步骤。对于C语言的代码,是用“cc1”这个程序来完成这两步,对于C++代码,对应的程序为“cc1plus”。gcc这个命令只是后台程序的包装,根据不同的参数去调用:预编译编译程序——cc1,汇编器——as,连接器——ld。

    C语言的代码,经编译后产生的文件名为xxx.s。

    三、汇编:将汇编代码转变成机器可以执行的指令(机器码文件)。
    汇编器的汇编过程相对于编译器来说更简单,没有复杂的语法,也没有语义,更不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译过来,汇编过程有汇编器as完成。

    经汇编之后,产生目标文件(与可执行文件格式几乎一样)xxx.o(Windows下)、xxx.obj(Linux下)。

    但是,经过预编译、编译、汇编之后,生成机器可以执行的目标文件之后,还有一个问题——变量a和数组arr的地址还没有确定。这就需要链接器来搞定啦~

    四、链接:
    1、历史过程:曾经,程序猿门在编程时,使用纸带作为最原始的存储设备,每当程序需要修改时,都要重新扎一条纸带,扎孔的表示1,不扎的是0,一串串1和0就组成了各种各样的指令——跳转等等….
    每一次的修改都非常痛苦,所以先知们就发明了汇编语言,这种编程语言方便之处在于符号的引用,表示跳转指令不再需要记住一串串0和1,终于可以使用符号——foo来表示这个动作了!
    随着汇编语言的普及,程序的代码量也就开始快速膨胀了,汇编语言说它也撑不住了….不过还好,高级编程语言Fortran、C、C++等一个接一个地问世,语言越来越方便了,追求perfect的人们就想:代码咋写更好呢?可不可以把代码按照功能的不同,分成不同的部分,便于日后的修改和重复使用呢?
    有了这个启发,程序猿们越来越得心应手,他们开始把代码按照功能和性质划分,分别形成不同的功能模块,不同的模块之间又按照各种结构来组织。
    发展到如今,软件的规模越来越大,代码动辄数百万行代码,放在一个模块那是万万不行的,维护起来会非常麻烦,所有现在的大型软件往往拥有成千上万的模块,
    模块之间相互独立又相互依赖。
    新的问题来了,一个程序被分割成这么多模块,最后要怎么把这些模块组合形成一个单一的程序?
    答案就是:模块之间,符号的引用
    这就像是一张画有大树的拼图,叶子、枝干、根系都零散的分布在那些拼图碎片上,想要看到完整的大树,我们就会耐心地把那些碎片拼合在一起。

    这里写图片描述

    这些模块之间同样如此,它们依靠那些凸起和凹陷联系在一起,最终组合成一个完整的程序,这样的过程称为——链接。

    这样基于符号的模块化,使得链接过程在整个程序开发中显得十分重要和突出…..

    2、下面就静态链接,进行分析。
    1.链接:“组装”模块的过程。
    2.链接的内容:把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确地衔接。(就像拼图,凸起和凹槽的位置一定一一对应,否则…)
    3.链接的过程:地址和空间的分配、符号决议(也叫“符号绑定”,倾向于动态链接)和重定位
    以gcc编译器为例,看基本的链接过程:

    这里写图片描述

    .c文件经过编译器、汇编器之后得到目标文件.o,目标文件再与库进行链接得到可执行文件.out。
    库其实就是一组目标文件的打包,这些目标文件中都是一些常用的代码。

    我们在fun.c模块中定义了函数foo(),在main.c模块中引用了foo()函数,在编译过程当中,编译器并不知道main.c中foo()的地址,所以将调用foo()的指令的目标地址部分搁置,
    等到了链接的阶段,链接器会去找到foo()定义的那个模块,在main.o中填入正确的函数地址,这个修改地址的过程被叫做“重定位”,每个被修正的地方叫“重定位入口”。

    这里写图片描述

    以上就是一个程序从源代码到可执行程序的大致过程,这是博主根据《程序员的自我修养——链接、装载与库》来整理的,有兴趣的同学可以自己去琢磨琢磨~





    原博客地址:https://blog.csdn.net/qq_39755395/article/details/78293733
    转载注明出处
    展开全文
  • 网上有很多的人说编程有多么多么无聊。。。。So Boring ! 。。。其实小编想说:不要管别人怎么说,别人说什么,做你自己喜欢做的事就好。坚持下来,你会发现编程的乐趣的。...当然,如果你觉得学习编程语言很痛苦,...

    网上有很多的人说编程有多么多么无聊。。。。So Boring ! 。。。其实小编想说:不要管别人怎么说,别人说什么,做你自己喜欢做的事就好。坚持下来,你会发现编程的乐趣的。。。。当然,如果你觉得学习编程语言很痛苦,坚持了一段时间后无果,南无果断放弃未必不是一个好的选择。。。。哈哈哈哈。。。

    英国作家和评论家约翰逊说过:

    Great works are performed not by strength , but by perseverance.

    完成伟大的事业不在于体力,而在于坚韧不拔的毅力。 ——Samuel Johnson

    C语言10个经典小程序——小白必备!

    如果想学c++并想学好,可以加这个群,首先是玖四捌,中间是玖伍四,最后是四捌四,里面有大量的学习资料可以下载。

    【程序1】

    题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

    1.程序分析:可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去

    掉不满足条件的排列。

    2.程序源代码:

    #include<stdio.h>

    void main()

    {

    int i,j,k;

    printf(" ");

    for(i=1;i<5;i++) /*以下为三重循环*/

     for(j=1;j<5;j++) 

    for (k=1;k<5;k++)

    {

    if (i!=k&&i!=j&&j!=k) /*确保i、j、k三位互不相同*/

    printf("%d,%d,%d ",i,j,k);

    }

    }

    【程序2】

    题目:输入某年某月某日,判断这一天是这一年的第几天?

    1.程序分析:以3月5日为例,应该先把前两个月的加起来,然后再加上5天即本年的第几天,特殊

    情况,闰年且输入月份大于3时需考虑多加一天。

    2.程序源代码:

    #include<stdio.h>

    void main()

    {

    int day,month,year,sum,leap;

    printf(" please input year,month,day ");

    scanf("%d,%d,%d",&year,&month,&day);

    switch(month)/*先计算某月以前月份的总天数*/

    {

     case 1:sum=0;break;

     case 2:sum=31;break;

     case 3:sum=59;break;

     case 4:sum=90;break;

     case 5:sum=120;break;

     case 6:sum=151;break;

     case 7:sum=181;break;

     case 8:sum=212;break;

     case 9:sum=243;break;

     case 10:sum=273;break;

     case 11:sum=304;break;

     case 12:sum=334;break;

     defaultrintf("data error");break;

    }

    sum=sum+day; /*再加上某天的天数*/

     if(year%400==0||(year%4==0&&year%100!=0))/*判断是不是闰年*/

    leap=1;

     else

    leap=0;

    if(leap==1&&month>2)/*如果是闰年且月份大于2,总天数应该加一天*/

    sum++;

    printf("It is the %dth day.",sum); }

    【程序3】

    题目:输入三个整数x,y,z,请把这三个数由小到大输出。

    1.程序分析:我们想办法把最小的数放到x上,先将x与y进行比较,如果x>y则将x与y的值进行交换,

    然后再用x与z进行比较,如果x>z则将x与z的值进行交换,这样能使x最小。

    2.程序源代码:

    #include<stdio.h>

    void main()

    {

    int x,y,z,t;

    scanf("%d%d%d",&x,&y,&z);

    if (x>y)

    /*交换x,y的值*/

    if(x>z)

    /*交换x,z的值*/

    if(y>z)

    /*交换z,y的值*/

    printf("small to big: %d %d %d ",x,y,z);

    }

    C语言10个经典小程序——小白必备!

     

    【程序4】

    题目:用*号输出字母C的图案。

    1.程序分析:可先用<|>*<|>号在纸上写出字母C,再分行输出。

    2.程序源代码:

    #include<stdio.h>

    void main()

    {

    printf("Hello C-world! ");

    printf(" **** ");

    printf(" * ");

    printf(" * ");

    printf(" **** ");

    }

    【程序5】

    题目:输出特殊图案,请在c环境中运行,看一看,Very Beautiful!

    1.程序分析:字符共有256个。不同字符,图形不一样。

    2.程序源代码:

    #include<stdio.h>

    void main()

    {

    char a=176,b=219;

    printf("%c%c%c%c%c ",b,a,a,a,b);

    printf("%c%c%c%c%c ",a,b,a,b,a);

    printf("%c%c%c%c%c ",a,a,b,a,a);

    printf("%c%c%c%c%c ",a,b,a,b,a);

    printf("%c%c%c%c%c ",b,a,a,a,b); }

    【程序6】

    题目:输出9*9口诀。

    1.程序分析:分行与列考虑,共9行9列,i控制行,j控制列。

    2.程序源代码:

    #include<stdio.h>

    void main()

    {

     int i,j,result;

     printf(" ");

     for (i=1;i<10;i++)

    { for(j=1;j<10;j++)

    {

    result=i*j;

    printf("%d*%d=%-3d",i,j,result); /*-3d表示左对齐,占3位*/

    }

    printf(" "); /*每一行后换行*/

    }

    }

    C语言10个经典小程序——小白必备!

    如果想学c++并想学好,可以加这个群,715383213,里面有大量的学习资料可以下载。

    【程序7】

    题目:要求输出国际象棋棋盘。

    1.程序分析:用i控制行,j来控制列,根据i+j的和的变化来控制输出黑方格,还是白方格。

    2.程序源代码:

    #include<stdio.h>

    void main()

    {

    int i,j;

    for(i=0;i<8;i++)

     {

    for(j=0;j<8;j++)

    if((i+j)%2==0)

    printf("%c%c",219,219);

    else

    printf(" ");

    printf(" ");

    }

    }

    【程序8】

    题目:打印楼梯,同时在楼梯上方打印两个笑脸。

    1.程序分析:用i控制行,j来控制列,j根据i的变化来控制输出黑方格的个数。

    2.程序源代码:

    #include<stdio.h>

    void main()

    {

    int i,j;

    printf(" ");/*输出两个笑脸*/

    for(i=1;i<11;i++)

     {

     for(j=1;j<=i;j++)

    printf("%c%c",219,219);

     printf(" ");

    }

    }

    9.求两个数的最小公倍数。

    最小公倍数和最大公约数之间的关系为两数的乘积除以两数的最大公约数的值即为两个数的最小公倍数

    #include<stdio.h>

    int main()

    {

    int a, b, c,d;

    int t;

    printf("请输入两个整数:");

    scanf("%d%d", &a, &b);

    d = a*b;

    if (a > b&&a%b == 0)

    {

    printf("最小公倍数为:%d ", a);

    }

    else if (a < b);

    {

    t = a;

    a = b;

    b = t;

    }

    c = a%b;

    while (c != 0)

    {

    a = b;

    b = c;

    c = a%b;

    }

    printf("最小公倍数为:%d ",d/b );

    return 0;

    }

    C语言10个经典小程序——小白必备!

     

    10.斐波那契数列

    Fibonacci 数列的特点是第1、2个数为1、1;从第三个数开始,该数是前两个数之和,求这个数列的前30个元素

    #include<stdio.h>

    int main()

    {

    int i;

    int long F[31];

    F[1] = 1; //第一个和第二个数为1

    F[2] = 1;

    for (i = 3; i < 31; i++)

    {

    F[i] = F[i - 1] + F[i - 2]; //从第三项开始,每项为前三项之和

    }

    for (i = 1; i < 31; i++)

    {

    printf("%-15d", F[i]);

    if (i % 5 == 0) //控制每行输出5个值

    {

    printf(" ");

    }

    }

    return 0;

    }

    写在最后

    关于怎么快速学C/C++,可以加下小编的C/C++学习群:715383213,,邀请码:CSDN,不管你是小白还是大牛,小编我都欢迎,不定期分享干货,欢迎初学和进阶中的小伙伴。

     

    每天晚上20:00都会开直播给大家分享C/C++游戏编程学习知识和路线方法,群里会不定期更新最新的教程和学习方法,最后祝所有程序员都能够走上人生巅峰,让代码将梦想照进现实

    展开全文
  • 程序从入门到快速开发小程序项目

    万次阅读 多人点赞 2018-08-28 23:01:25
    备注:小程序只是突发灵感兴趣弄的,并非专业研究小程序,其实小程序API并不多,不复杂,扩展无非就是JS了。 最近用了大概两天左右的时间看了小程序的官方文档:https://mp.weixin.qq.com/cgi-bin/wx 然后有目标的...

    作者:谭东

    备注:小程序只是突发灵感兴趣弄的,并非专业研究小程序,其实小程序API并不多,不复杂,扩展无非就是JS了。

    最近用了大概两天左右的时间看了小程序的官方文档:https://mp.weixin.qq.com/cgi-bin/wx

    然后有目标的进行实践,也就是要实现个你想要的小程序,这样边实践边学习才能够有疑问,才能够更快的理解和学习小程序开发。所以后续几天就开始小程序实践和学习之旅了,期间也遇到了一些问题并且学到了很多基础知识和解决方案。接下来给大家讲解下小程序的开发基本知识和扩展知识。

    官方文档其实写的基本很详细了,我们先从工具开始说起。

    1、小程序开发者工具。

    这个工具集成了公众号网页调试和小程序调试两种开发模式。我这里使用了Beta版本,没有用正式版。因为我想体验使用其中的Git版本管理功能。下载地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/beta.html

    下载安装好后,先要微信扫描登录。然后选择小程序项目。

    新建小程序项目。

    选择新建小程序的项目目录,AppID没有注册的话,可以先点击下面的使用测试号即可,不影响开发。

    大致的工具界面如下图,新版有版本管理。红色圈起来的为小程序项目的一个页面包含的元素:

    工具用起来很方便、简单、直接。详细用法就不说了,主要的功能大概说下。左侧是模拟器,可以模拟安卓手机和苹果手机的效果,因为有些小程序组件在安卓和苹果上显示是有区别的,大家可以注意下。圈红的为小程序一个页面的基本组成文件元素:xx.js、xx.wxml、xx.wxss、xx.json。其实就是有JS文件、HTML文件(xx.wxml)、CSS样式文件(xx.wxss)和配置文件(xx.json)组成,非常的容易理解。我们就是在使用小程序的组件、控件来绘制UI布局,主要是xx.wxml和xx.wxss文件。xx.js负责生命周期函数和事件处理,例如:点击事件、数据请求、数据绑定等等逻辑操作。

    我们在编写完后,可以点击工具栏上的预览按钮,扫描二维码在真机上体验,也可以直接用左侧的模拟器时时预览即可。

    看完了工具,我们看下基本开发的要素和需要注意的问题吧,以免新手再次重蹈覆辙。

    看下默认的新建后的结构:

    app.json是小程序全局配置文件,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。

    大致代码结构如下:

    {
      "pages":[
        "pages/index/index",
        "pages/logs/logs"
      ],
      "window":{
        "backgroundTextStyle":"light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "WeChat",
        "navigationBarTextStyle":"black"
      }
    }

    pages是配置小程序所有页面,类似于注册清单。window是全局的窗口配置,如颜色、标题等等。当然每个页面也可以自己单独配置,就是页面名称.json文件。例如:page.json。不过需要注意的是,单独页面配置的json无需写window这个关键字,直接如下代码所示:

    {
      "backgroundTextStyle": "light",
      "navigationBarBackgroundColor": "#34495e",
      "navigationBarTitleText": "日记",
      "navigationBarTextStyle": "white",
      "enablePullDownRefresh": true,
      "backgroundColor": "#34495e"
    }

    那么再看工具配置文件project.config.json。

    通常大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如界面颜色、编译配置等等,当你换了另外一台电脑重新安装工具的时候,你还要重新配置。考虑到这点,小程序开发者工具在每个项目的根目录都会生成一个 project.config.json,你在工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。具体详细配置大家可以看小程序官方文档有详细介绍。

    还有一个app.wxss和app.js。这个app.wxss就是全局的样式文件,也就是css文件,当然和页面配置文件一样,每个页面可以单独写页面名称.wxss。

    WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改。

    新增了尺寸单位。在写 CSS 样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。WXSS 在底层支持新的尺寸单位 rpx ,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差。

    提供了全局的样式和局部样式。和前边 app.json, page.json 的概念相同,你可以写一个 app.wxss 作为全局样式,会作用于当前小程序的所有页面,局部页面样式 page.wxss 仅对当前页面生效。

    此外 WXSS 仅支持部分 CSS 选择器

    再来看app.js,很明显是一个js文件。负责UI交互、数据绑定更新、网络请求、页面生命周期等等操作相关的都在这里。当然每个页面都有自己单独的.js文件,这个app.js可以做一些需要全局共享和操作的逻辑在里面。在这里可以调用微信小程序的很多API,也可以自己写js方法使用。

    那么我们看下一个页面的组成,基本上就是下图这些结构元素。有界面、有样式、有js交互、有配置。

    每新增一个页面都要在app.json里添加注册进去。

    一个.js文件里有生命周期的管理函数,可以在这里面做相应的操作。

    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        
      },
    
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function (options) {
        
      },
    
      /**
       * 生命周期函数--监听页面初次渲染完成
       */
      onReady: function () {
        
      },
    
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function () {
        
      },
    
      /**
       * 生命周期函数--监听页面隐藏
       */
      onHide: function () {
        
      },
    
      /**
       * 生命周期函数--监听页面卸载
       */
      onUnload: function () {
        
      },
    
      /**
       * 页面相关事件处理函数--监听用户下拉动作
       */
      onPullDownRefresh: function () {
        
      },
    
      /**
       * 页面上拉触底事件的处理函数
       */
      onReachBottom: function () {
        
      },
    
      /**
       * 用户点击右上角分享
       */
      onShareAppMessage: function () {
        
      }
    })

    我们看下最简单的一个index.wxml页面,可以当做是Html页面,只有一个text控件,里面的bindtap就是点击事件的绑定。

    <!--index.wxml-->
    <view class="container">
      <view class="usermotto">
        <text class="user-motto" bindtap='click'>{{motto}}</text>
      </view>
    </view>

    那么这个class就是index.wxss里的样式文件。里面的{{motto}}就是指向index.js里的data里定义的一个变量。小程序都是通过{{..}}两个大括号包括一个英文名字来进行变量绑定的。这样我们就可以动态更换里面的显示内容了。那么怎么更新内容呢?

    在js里使用下面的this.setData方式动态更新刷新数据:

    this.setData({ motto: "名字" })
    /**index.wxss**/
    .userinfo {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    
    .userinfo-avatar {
      width: 128rpx;
      height: 128rpx;
      margin: 20rpx;
      border-radius: 50%;
    }
    
    .userinfo-nickname {
      color: #aaa;
    }
    
    .usermotto {
      margin-top: 200px;
    }

    再看下index.

    js文件。

    //index.js
    //获取应用实例
    const app = getApp()
    
    Page({
      data: {
        motto: 'Hello World',
      },
      
      //事件处理函数
      click: function() {
        wx.navigateTo({
          url: '../logs/logs'
        })
      },
        
    })

    Page函数是必须要有的,里面包含data:{  ... },用于放置数据、常量、变量等等。这里的click:function就是我们定义的点击事件。wx.navigateTo...方法就是小程序的官方API,具体其他API的用法和返回参数是什么可以看官方API文档,很详细。

    观察下,上面有个声明了app这个常量。这个就是app.js里拿到的全局管理调用app.js里的方法和常量用的。很多需要存储和全局读写、处理的都可以进行操作以及放置在app.js里。在 JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。通过全局函数 getApp() 可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置。

    Page({
      data: { // 参与页面渲染的数据
        logs: []
      },
      onLoad: function () {
        // 页面渲染后执行
      }
    })

    小程序的组件和控件有很多,可以看做是Html的标签,对称方式使用。具体组件特性看官方文档:

    https://developers.weixin.qq.com/miniprogram/dev/component/

    为了让开发者可以很方便的调起微信提供的能力,例如获取用户信息、微信支付等等,小程序提供了很多 API 给开发者,例如:

    要获取用户的地理位置时,只需要:

    wx.getLocation({
      type: 'wgs84',
      success: (res) => {
        var latitude = res.latitude // 经度
        var longitude = res.longitude // 纬度
      }
    })

    调用微信扫一扫能力,只需要:

    wx.scanCode({
      success: (res) => {
        console.log(res)
      }
    })

    需要注意的是:多数 API 的回调都是异步,你需要处理好代码逻辑的异步问题。更多API说明和用法,看官方文档。

    https://developers.weixin.qq.com/miniprogram/dev/api/

    页面的生命周期,我之前说过了,比较重要,大家可以看下理解下。

    看下逻辑层需要注意的。除了页面的生命周期,还有页面的监听事件。onPullDownRefresh():监听用户下拉刷新事件。

    需要在app.json的window选项中或页面配置中开启enablePullDownRefresh。
    可以通过wx.startPullDownRefresh触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
    当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。

    onReachBottom():监听用户上拉触底事件。

    可以在app.json的window选项中或页面配置中设置触发距离onReachBottomDistance,默认为50px。
    在触发距离内滑动期间,本事件只会被触发一次。

    onPageScroll(Object):监听用户滑动页面事件。

    onShareAppMessage(Object):

    监听用户点击页面内转发按钮(<button> 组件 open-type="share")或右上角菜单“转发”按钮的行为,并自定义转发内容。

    注意:只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮。

    onTabItemTap(Object):点击 tab 时触发。

    Page.prototype.setData(Object data, Function callback):setData 函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)。

    Object 以 key: value 的形式表示,将 this.data 中的 key 对应的值改变成 value。

    其中 key 可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如 array[2].message,a.b.c.d,并且不需要在 this.data 中预先定义。

    注意:

    直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
    仅支持设置可 JSON 化的数据。
    单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
    请不要把 data 中任何一项的 value 设为 undefined ,否则这一项将不被设置并可能遗留一些潜在问题。

    接下来看下小程序里的路由、跳转。

    主要有这几种方式:

    这几种方式url都可以传递参数。

    wx.navigateTo:保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。注意:目前页面路径最多只能十层。

    wx.redirectTo(OBJECT):关闭当前页面,跳转到应用内的某个页面。如果你想让页面没有返回按钮,不能返回的话,就用这个跳转方式吧。

    wx.reLaunch(OBJECT):关闭所有页面,打开到应用内的某个页面。

    wx.switchTab(OBJECT):跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。

    wx.navigateBack(OBJECT):关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。

    注意:

    1、navigateTo, redirectTo 只能打开非 tabBar 页面。
    2、switchTab 只能打开 tabBar 页面。
    3、reLaunch 可以打开任意页面。
    4、页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
    5、调用页面路由带的参数可以在目标页面的onLoad中获取。

    再看下模块化。

    可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口。

    需要注意的是:

    exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造成未知的错误。所以更推荐开发者采用 module.exports 来暴露模块接口,除非你已经清晰知道这两者的关系。小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中。

    // common.js
    function sayHello(name) {
      console.log(`Hello ${name} !`)
    }
    function sayGoodbye(name) {
      console.log(`Goodbye ${name} !`)
    }
    
    module.exports.sayHello = sayHello
    exports.sayGoodbye = sayGoodbye

    ​在需要使用这些模块的文件中,使用 require(path) 将公共代码引入:

    var common = require('common.js')
    Page({
      helloMINA: function() {
        common.sayHello('MINA')
      },
      goodbyeMINA: function() {
        common.sayGoodbye('MINA')
      }
    })

    注意:require 暂时不支持绝对路径。

    接下来看下小程序的视图层,也就是wxml和wxss。

    框架的视图层由 WXML 与 WXSS 编写,由组件来进行展示。将逻辑层的数据反应成视图,同时将视图层的事件发送给逻辑层。

    WXML(WeiXin Markup language) 用于描述页面的结构。

    WXS(WeiXin Script) 是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。

    WXSS(WeiXin Style Sheet) 用于描述页面的样式。

    组件(Component)是视图的基本组成单元。

    这里挑几个比较重要的来说。首先是列表渲染,就是我们想实现一个List列表展示的时候,要进行List数据绑定,item数据绑定、可能还会涉及到模板和数据传递等等。

    列表渲染:

    <!--wxml-->
    <view wx:for="{{array}}"> {{item}} </view>
    // page.js
    Page({
      data: {
        array: [1, 2, 3, 4, 5]
      }
    })

    在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。

    <view wx:for="{{array}}">
      {{index}}: {{item.message}}
    </view>

    使用 wx:for-item 可以指定数组当前元素的变量名,

    使用 wx:for-index 可以指定数组当前下标的变量名:

    <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
      {{idx}}: {{itemName.message}}
    </view>

    wx:for 也可以嵌套。类似 block wx:if,也可以将 wx:for 用在<block/>标签上,以渲染一个包含多节点的结构块。例如:

    <block wx:for="{{[1, 2, 3]}}">
      <view> {{index}}: </view>
      <view> {{item}} </view>
    </block>

    如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input/> 中的输入内容,<switch/> 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。

    wx:key 的值以两种形式提供:

    字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
    保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
    当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

    如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

    条件渲染:

    <!--wxml-->
    <view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
    <view wx:elif="{{view == 'APP'}}"> APP </view>
    <view wx:else="{{view == 'MINA'}}"> MINA </view>
    // page.js
    Page({
      data: {
        view: 'MINA'
      }
    })

    在框架中,使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块。

    因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。

    相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。

    一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。

    还可能会涉及到模板template,可以在模板中定义代码片段,然后在不同的地方调用。

    使用 name 属性,作为模板的名字。然后在<template/>内定义代码片段,如:

    <!--
      index: int
      msg: string
      time: string
    -->
    <template name="msgItem">
      <view>
        <text> {{index}}: {{msg}} </text>
        <text> Time: {{time}} </text>
      </view>
    </template>

    使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,如:

    <template is="msgItem" data="{{...item}}"/>
    Page({
      data: {
        item: {
          index: 0,
          msg: 'this is a template',
          time: '2016-09-15'
        }
      }
    })

    is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板:

    <template name="odd">
      <view> odd </view>
    </template>
    <template name="even">
      <view> even </view>
    </template>
    
    <block wx:for="{{[1, 2, 3, 4, 5]}}">
    	<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
    </block>

    模板拥有自己的作用域,只能使用 data 传入的数据以及模版定义文件中定义的 <wxs /> 模块。

    另外,target(触发事件的源组件)和currentTarget(事件绑定的当前组件)也比较重要,大家可以自行看例子和文档学习。

    dataset:在组件中可以定义数据,这些数据将会通过事件传递给 SERVICE。 书写方式: 以data-开头,多个单词由连字符-链接,不能有大写(大写会自动转成小写)如data-element-type,最终在 event.currentTarget.dataset 中会将连字符转成驼峰elementType。

    <view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view>
    Page({
      bindViewTap:function(event){
        event.currentTarget.dataset.alphaBeta === 1 // - 会转为驼峰写法
        event.currentTarget.dataset.alphabeta === 2 // 大写会转为小写
      }
    })

    小程序的引用,如引用外部css文件、引入js文件、引入wxml模板文件等等。

    WXML 提供两种文件引用方式import和include。

    import可以在该文件中使用目标文件定义的template,如:在 item.wxml 中定义了一个叫item的template:

    <!-- item.wxml -->
    <template name="item">
      <text>{{text}}</text>
    </template>

    在 index.wxml 中引用了 item.wxml,就可以使用item模板:

    <import src="item.wxml"/>
    <template is="item" data="{{text: 'forbar'}}"/>

    import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。

    include 可以将目标文件除了 <template/> <wxs/> 外的整个代码引入,相当于是拷贝到 include 位置,如:

    <!-- index.wxml -->
    <include src="header.wxml"/>
    <view> body </view>
    <include src="footer.wxml"/>
    <!-- header.wxml -->
    <view> header </view>
    <!-- footer.wxml -->
    <view> footer </view>

    再讲一个wxs文件,不太常用。WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。

    注意:
    1、wxs 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
    2、wxs 与 javascript 是不同的语言,有自己的语法,并不和 javascript 一致。
    3、wxs 的运行环境和其他 javascript 代码是隔离的,wxs 中不能调用其他 javascript 文件中定义的函数,也不能调用小程序提供的API。
    4、wxs 函数不能作为组件的事件回调。
    5、由于运行环境的差异,在 iOS 设备上小程序内的 wxs 会比 javascript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
    以下是一些使用 WXS 的简单示例。

    页面渲染:

    <!--wxml-->
    <wxs module="m1">
    var msg = "hello world";
    
    module.exports.message = msg;
    </wxs>
    
    <view> {{m1.message}} </view>

    页面输出:

    hello world

    数据处理:

    // page.js
    Page({
      data: {
        array: [1, 2, 3, 4, 5, 1, 2, 3, 4]
      }
    })
    <!--wxml-->
    <!-- 下面的 getMax 函数,接受一个数组,且返回数组中最大的元素的值 -->
    <wxs module="m1">
    var getMax = function(array) {
      var max = undefined;
      for (var i = 0; i < array.length; ++i) {
        max = max === undefined ? 
          array[i] : 
          (max >= array[i] ? max : array[i]);
      }
      return max;
    }
    
    module.exports.getMax = getMax;
    </wxs>
    
    <!-- 调用 wxs 里面的 getMax 函数,参数为 page.js 里面的 array -->
    <view> {{m1.getMax(array)}} </view>

    页面会输出5。

    WXS 代码可以编写在 wxml 文件中的 <wxs> 标签内,或以 .wxs 为后缀名的文件内。

    每一个 .wxs 文件和 <wxs> 标签都是一个单独的模块。每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见。一个模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现。

    可以直接创建 .wxs 文件,在其中直接编写 WXS 脚本。

    var foo = "'hello world' from comm.wxs";
    var bar = function(d) {
      return d;
    }
    module.exports = {
      foo: foo,
      bar: bar
    };

    在.wxs文件里面编写了 WXS 代码。该 .wxs 文件可以被其他的 .wxs 文件 或 WXML 中的 <wxs> 标签引用。

    每个 wxs 模块均有一个内置的 module 对象。exports:通过该属性,可以对外共享本模块的私有变量与函数。

    // /pages/tools.wxs
    
    var foo = "'hello world' from tools.wxs";
    var bar = function (d) {
      return d;
    }
    module.exports = {
      FOO: foo,
      bar: bar,
    };
    module.exports.msg = "some msg";
    <!-- page/index/index.wxml -->
    
    <wxs src="./../tools.wxs" module="tools" />
    <view> {{tools.msg}} </view>
    <view> {{tools.bar(tools.FOO)}} </view>

    页面输出:

    some msg
    'hello world' from tools.wxs

    在.wxs模块中引用其他 wxs 文件模块,可以使用 require 函数。

    引用的时候,要注意如下几点:

    1、只能引用 .wxs 文件模块,且必须使用相对路径。
    2、wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 wxs 模块对象。
    3、如果一个 wxs 模块在定义之后,一直没有被引用,则该模块不会被解析与运行。

    module 属性是当前 <wxs> 标签的模块名。在单个 wxml 文件内,建议其值唯一。有重复模块名则按照先后顺序覆盖(后者覆盖前者)。不同文件之间的 wxs 模块名不会相互覆盖。module 属性值的命名必须符合下面两个规则:

    1、首字符必须是:字母(a-zA-Z),下划线(_)。
    2、剩余字符可以是:字母(a-zA-Z),下划线(_), 数字(0-9)。

    src 属性可以用来引用其他的 wxs 文件模块。引用的时候,要注意如下几点:

    1、只能引用 .wxs 文件模块,且必须使用相对路径。
    2、wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 wxs 模块对象。
    3、如果一个 wxs 模块在定义之后,一直没有被引用,则该模块不会被解析与运行。

    注意:
    1、<wxs> 模块只能在定义模块的 WXML 文件中被访问到。使用 <include> 或 <import> 时,<wxs> 模块不会被引入到对应的 WXML 文件中。
    2、<template> 标签中,只能使用定义该 <template> 的 WXML 文件中定义的 <wxs> 模块。

    再看下官方给出的小程序性能优化建议。

    setData 是小程序开发中使用最频繁的接口,也是最容易引发性能问题的接口。在介绍常见的错误用法前,先简单介绍一下 setData 背后的工作原理。

    小程序的视图层目前使用 WebView 作为渲染载体,而逻辑层是由独立的 JavascriptCore 作为运行环境。在架构上,WebView 和 JavascriptCore 都是独立的模块,并不具备数据直接共享的通道。当前,视图层和逻辑层的数据传输,实际上通过两边提供的 evaluateJavascript 所实现。即用户传输的数据,需要将其转换为字符串形式传递,同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立环境。而 evaluateJavascript 的执行会受很多方面的影响,数据到达视图层并不是实时的。

    常见的 setData 操作错误:
    1. 频繁的去 setData。

    在我们分析过的一些案例里,部分小程序会非常频繁(毫秒级)的去setData,其导致了两个后果:Android 下用户在滑动时会感觉到卡顿,操作反馈延迟严重,因为 JS 线程一直在编译执行渲染,未能及时将用户操作事件传递到逻辑层,逻辑层亦无法及时将操作处理结果及时传递到视图层;
    渲染有出现延时,由于 WebView 的 JS 线程一直处于忙碌状态,逻辑层到页面层的通信耗时上升,视图层收到的数据消息时距离发出时间已经过去了几百毫秒,渲染的结果并不实时;
    2. 每次 setData 都传递大量新数据。

    由setData的底层实现可知,我们的数据传输实际是一次 evaluateJavascript 脚本过程,当数据量过大时会增加脚本的编译执行时间,占用 WebView JS 线程,

    3. 后台态页面进行 setData。

    当页面进入后台态(用户不可见),不应该继续去进行setData,后台态页面的渲染用户是无法感受的,另外后台态页面去setData也会抢占前台页面的执行。

    图片资源:
    目前图片资源的主要性能问题在于大图片和长列表图片上,这两种情况都有可能导致 iOS 客户端内存占用上升,从而触发系统回收小程序页面。

    图片对内存的影响:
    在 iOS 上,小程序的页面是由多个 WKWebView 组成的,在系统内存紧张时,会回收掉一部分 WKWebView。从过去我们分析的案例来看,大图片和长列表图片的使用会引起 WKWebView 的回收。

    图片对页面切换的影响:
    除了内存问题外,大图片也会造成页面切换的卡顿。我们分析过的案例中,有一部分小程序会在页面中引用大图片,在页面后退切换中会出现掉帧卡顿的情况。当前我们建议开发者尽量减少使用大图片资源。

    代码包大小的优化:
    小程序一开始时代码包限制为 1MB,但我们收到了很多反馈说代码包大小不够用,经过评估后我们放开了这个限制,增加到 2MB 。代码包上限的增加对于开发者来说,能够实现更丰富的功能,但对于用户来说,也增加了下载流量和本地空间的占用。开发者在实现业务逻辑同时也有必要尽量减少代码包的大小,因为代码包大小直接影响到下载速度,从而影响用户的首次打开体验。除了代码自身的重构优化外,还可以从这两方面着手优化代码大小:

    控制代码包内图片资源:
    小程序代码包经过编译后,会放在微信的 CDN 上供用户下载,CDN 开启了 GZIP 压缩,所以用户下载的是压缩后的 GZIP 包,其大小比代码包原体积会更小。 但我们分析数据发现,不同小程序之间的代码包压缩比差异也挺大的,部分可以达到 30%,而部分只有 80%,而造成这部分差异的一个原因,就是图片资源的使用。GZIP 对基于文本资源的压缩效果最好,在压缩较大文件时往往可高达 70%-80% 的压缩率,而如果对已经压缩的资源(例如大多数的图片格式)则效果甚微。

    及时清理没有使用到的代码和资源:
    在日常开发的时候,我们可能引入了一些新的库文件,而过了一段时间后,由于各种原因又不再使用这个库了,我们常常会只是去掉了代码里的引用,而忘记删掉这类库文件了。目前小程序打包是会将工程下所有文件都打入代码包内,也就是说,这些没有被实际使用到的库文件和资源也会被打入到代码包里,从而影响到整体代码包的大小。

    下面将会讲解一些开发中遇到的问题:

    列表绑定渲染数据、跳转传值、小程序的工具调试使用、小程序授权弹窗、小程序客服反馈、小程序支付、小程序获取unionId和openId、小程序第三方框架、UI库等。

     

     

    这个是开源share的,github地址:https://github.com/jaychou2012/wx_note

     

     

    持续更新中,敬请关注... ...

    展开全文
  • discuz论坛小程序

    2020-07-30 23:33:22
    discuz论坛小程序,非常简单好用。
  • 什么是Web应用程序

    万次阅读 2017-11-22 12:11:33
    一 Web应用程序 Web应用程序是一种可以通过Web访问的应用程序。Web应用程序的一个最大好处是用户可以很容易访问应用程序。用户只需要有浏览器即可,不需要再按照其他软件。   二 为什么要学习Web应用程序 Web...
  • 程序实现原理解析

    万次阅读 多人点赞 2020-09-05 17:35:38
    概述作为一名前端开发,如果你还停留在应用开发层面,那你就OUT了,快来跟我一起探讨下小程序框架本身底层实现的一些技术细节吧,让我们从小程序的运行机制来深度了解小程序。 小程序是基于WEB规范,采用HTML,CSS和...
  • 程序的装入和链接

    千次阅读 2016-06-02 10:58:24
    程序的装入和链接 标签: phpweb服务优化extensionzendcache 2010-07-05 11:02 5787人阅读 评论(4) 收藏 举报 分类: 操作系统(4) 版权声明:本文为博主原创文章,未经博主允许...
  • 程序(进程)在cpu中的执行过程

    万次阅读 2020-05-20 22:14:53
    程序 程序编译好后,存于某个地方(外存), 当程序被要求运行时,做的事情如下: 1.把可执行程序相关数据代码等加载到内存的相应段? 2.等待cpu调度到此程序,也即是获取cpu的使用权 3.运行balabala... ...
  • import os import json import shutil import numpy as np import cv2 # 读图片(支持中文路径)->ndarray def myImread(path): return cv2.imdecode(np.fromfile(path, dtype=np.uint8), -1) ...
  • 微信小程序

    2020-08-11 09:04:27
    1.微信⼩程序的相关⽂件类型 微信⼩程序项⽬结构主要有四个⽂件类型,如下: .json后缀的json文件 .wxml 后缀的 WXML 模板文件 .wxss 后缀的 WXSS 样式文件 .js 后缀的 JS 脚本逻辑文件 app.json 必须要有这个⽂件...
  • #本文章仅用于记录本人学习过程,当作笔记来用,如有侵权请及时告知,谢谢! index页面有四个文件 接下来我们一个一个文件分析: 首先是index.js: 在这里插入代码片
  • 统一回复,我8月1日爬的数据,当然是8月的...总不能说是7月的吧。 平均工资 2020年8月全国招收程序员346036人。2020年8月全国程序员平均工资14357元,工资中位数12500元,其中95%的人的工资介于5250元到35000元。 ...
  • 近期热门微信小程序demo源码下载汇总(17/12.1-7)

    万次阅读 多人点赞 2018-02-05 09:45:45
    最新:热门微信小程序demo源码下载汇总(17/12.8-15) 热门微信小程序demo源码下载汇总(17/12.1-7),乃小程序学习分析必备资源!点击标题可直接跳转至下载: 新手必看: 开发者工具如何快速导入小程序demo...
  • 近期微信小程序demo源码下载汇总,乃居家旅行学习分析必备良品!点击标题可直接跳转至下载。帖子最下方可点击收藏 (微信小程序版本)可以在移动端阅读的git book 乐空空微信小程序版本 微信小程序案例:仿...
  • 设置标题栏 设置导航栏
  • 微信小程序教程系列

    万次阅读 多人点赞 2017-08-30 17:49:50
    微信小程序教程系列
1 2 3 4 5 ... 20
收藏数 9,200,272
精华内容 3,680,108
关键字:

程序