0

0

分享用canvas实现水流和水池动画的代码

零下一度

零下一度

发布时间:2017-05-17 14:28:12

|

6573人浏览过

|

来源于php中文网

原创

利用html 5的canvas标签绘制水流和水池动画

在利用HTML 5的canvas进行动画绘制之前,首先先介绍一下基本知识,包括canvas(如果对canvas比较熟悉的可以直接跳过该节)、oCanvas框架、精灵动画。在了解了以上的基本知识后,就可以开始利用canvas做动画了。

canvas标签简介

在这部分,东西比较多,比较杂,各个网站上都可以找到相关的简介,在此我就不造轮子了,菜鸟上的教程就挺不错的,另外推荐一个相当好的博文玩转html 5 canvas画图,这篇文章介绍的非常详细,推荐好好看看。

canvas框架oCanvas简介

canvas标签功能非常强大,既可以处理图片,又可以进行像素级的处理,完全可以取代浏览器端的flash,但是由于canvas发展还未完善,API还不是太全,元素的事件处理功能等还没有提供接口,在实现一些复杂功能时,尚需耗费许多精力,于是出现了许多第三方的基于canvas 的框架,这些框架相比于原生的canvas标签,有了更多简单易用的API,大大提高了我们编码的效率,在这里我选用的是oCanvas框架,相关的使用文档和demo都可以去上面的链接中查看。

精灵动画简介

精灵动画一般由一组自定义的属性值和3个子函数组成(init、advance、draw)。
三个函数的作用分别如下:
init:初始化精灵动画的属性值
advance:再画下一帧之前首先更新下一帧的状态值
draw:将advance函数中更新的状态值绘制到画布中
以上三个函数的执行顺序是:init->advance->draw->advance->draw->…..一直循环下去。下面我以一个随机产生上升气泡的例子说明一下上面的执行过程。

var constructor_bubble = function (settings, core) {

    return oCanvas.extend({
        core: core,
        shapeType: "rectangular",//下面定义了上面我们提到的三个函数:init(),advance(),draw()//在init中,我们map对象组、一个空的数组和一个代表高度的属性值
        init: function () {
            this.map=[
                {r:2,speed:3},
                {r:3,speed:3},
                {r:4,speed:3},
                {r:5,speed:3},
                {r:6,speed:3},
                {r:7,speed:3},
                {r:8,speed:3},
                {r:9,speed:3},
                {r:10,speed:3}
            ];                this.points=[];                this.height=this.container.height_now;

        },//下面是advance函数,在函数中我们利用if逻辑判断是否添加新的气泡以及进行气泡的位置更新,points数组利用队列的先进先出来存储气泡的 
        advance: function () {
            this.height=this.container.height_now;                if(Math.random()>0.95){                    var new_point={
                        x:this.start.x+this.offset*2*(Math.random()-0.5),
                        y:this.start.y-this.map[0].r,
                        r:this.map[0].r
                    };                    this.points.push(new_point);

                }            if(this.points.length>0){                for(var i=0;i<this.points.length;i++){                    this.points[i].x+=this.offset*2*(Math.random()-0.5);                    this.points[i].y-=3;                    if(this.start.y-this.points[i].y>this.height-this.points[i].r-33){                        this.points.shift();
                    }
                }
            }
        },//draw函数中,利用canvas的圆弧绘制指令,将points数组中存储的气泡依次画出        
        draw: function () {
            var canvas = this.core.canvas;

            canvas.lineJoin = 'round';
            canvas.lineWidth = this.GDwidth;
            canvas.strokeStyle = "#fff";            if(this.points.length>0){                for(var i=0;i<this.points.length;i++){
                    canvas.beginPath();
                    canvas.arc(this.points[i].x,this.points[i].y,5,0,2*Math.PI);
                    canvas.stroke();
                    canvas.closePath();
                }

            }

        }
    }, settings);
};
oCanvas.registerDisplayObject("bubble", constructor_bubble, "init");//下面是在应用中定义和添加上面定义的精灵动画,其中:start数组代表了气泡的产生点,container代表了气泡的存在区域var pp1=canvas.display.bubble({
     start:{x:425,y:566},
     container:SC02,
     width:50,
     offset:1,
     speed:5
 }).add();

水流和水池动画实现

下面详细介绍一下,项目中如何实现水流动画和水池动画的详细步骤:

水池动画的绘制

var constructor_show = function (settings, core) {
    return oCanvas.extend({
        core: core,
        shapeType: "rectangular",//上面四行都是oCanvas框架的结构语法/*下面init()、advance()、draw()分别是上节中说的动画精灵三元素,第一个用来初始化,第二个用来
更新操作,第三个用来绘制图像/动画在管道对象中,定义了一些属性,包括:x、y、height、width、start、
height_now、full、speed、fill、trail_flag、[trail]。其中x、y分别代表水池参考点相对画布左
上角的位置,height、width是水池的宽高属性,start表征了动画是否开始,height_now代表了水池中水
位的高度,full表征了水池是否填满,speed水池上涨的速度,fill水的颜色,trail_flag表征了该水池
是否是一个标准的矩形,如果不是的话,配合trail属性,指定水池的轮廓*/
       init: function () {     
       //默认动画关闭,水池full为0,当前高度为0
            this.start=0;            this.full=0;            this.height_now=0;
        },
        advance: function () {
        //如果水池未满并且是开启状态,水位未满就更新当前高度,否则将full置为1
           if(this.start==1&&this.full!=1){               if (this.height_now < this.Height) {                   this.height_now += this.speed;
               }               else {                   this.full = 1;
               }
           }
        },
        draw: function () {
            var canvas = this.core.canvas,            //先获得水池的位置
                origin = this.getOrigin(),
                x = this.abs_x - origin.x,
                y = this.abs_y - origin.y;            //开始绘制
            canvas.beginPath();
            canvas.strokeStyle = "#000";            if (this.trail_flag == 1) {            //如果是不规则图形,描出轮廓
                canvas.moveTo(this.trail[0].x_t, this.trail[0].y_t);                for (var i = 1; i < this.trail.length; i++) {
                    canvas.lineTo(this.trail[i].x_t, this.trail[i].y_t);
                }
                canvas.lineTo(this.trail[0].x_t, this.trail[0].y_t);
                canvas.clip();
            }            if (this.fill !== "") {            //设置颜色,绘制矩形水池
                canvas.fillStyle = this.fill;
                canvas.fillRect(x, y + this.Height - this.height_now, this.Width, this.height_now);
            }
            canvas.closePath();
        }
    }, settings);
};//将上面的动画精灵注册进oCanvas的display图形库中oCanvas.registerDisplayObject("SC_show", constructor_show, "init");

管道水流动画的绘制

在管道水流模型中,定义了以下的属性:
destination: 当前水流最前端的位置
cells: 管道路径数组
deta: 方向斜边长
deta_x: 方向x边长
deta_y: 方向y边长
flag_x: 余弦值
flag_y:正弦值
cellIndex: 当前绘制边的index
Speed: 水流速度
GDwidth:水流宽度
LineHeight:水流长度
x_now: 当前绘制点x坐标
y_now: 当前绘制点y坐标
firstX: 管道第一个点坐标x
firstY: 管道第一个点坐标y
beginHeight: 第一段水流的起点位置
endHeight: 上一段管道遗留未画完的水线
legacyHeight: 最前端点在上一个管道留下的长度
paused: 是否开始
fill:水流颜色
full:是否填满

init函数

//init函数主要完成初始化工作init: function () {
            this.x_now = this.cells[0].x_cell;
            this.y_now = this.cells[0].y_cell;
            this.firstX = this.x_now;
            this.firstY = this.y_now;
            this.endHeight = 0;
            this.beginHeight = 0;
            this.paused=0;
            this.full=0;

            this.cellIndex = 0;
            this.destination.x_d = this.cells[0].x_cell;
            this.destination.y_d = this.cells[0].y_cell;

            this.legacyHeight = -1;
            this.LineHeight=10;
            this.Speed=2*this.LineHeight/20;
        }

advance函数

//advance函数主要实现每次动画的刷新步进操作
 advance: function () {
            if(this.paused==1){
                if (this.cellIndex < this.cells.length - 1) {
                    this.deta_x = this.cells[this.cellIndex + 1].x_cell - this.cells[this.cellIndex].x_cell;
                    this.deta_y = this.cells[this.cellIndex + 1].y_cell - this.cells[this.cellIndex].y_cell;
                    this.deta = Math.sqrt(this.deta_x * this.deta_x + this.deta_y * this.deta_y);
                    this.flag_x = this.deta_x / this.deta;
                    this.flag_y = this.deta_y / this.deta;
                    if (this.legacyHeight >= 0) {
                        this.cellIndex++;
                        if (this.cellIndex < this.cells.length - 1) {
                            this.deta_x = this.cells[this.cellIndex + 1].x_cell - this.cells[this.cellIndex].x_cell;
                            this.deta_y = this.cells[this.cellIndex + 1].y_cell - this.cells[this.cellIndex].y_cell;
                            this.deta = Math.sqrt(this.deta_x * this.deta_x + this.deta_y * this.deta_y);
                            this.flag_x = this.deta_x / this.deta;
                            this.flag_y = this.deta_y / this.deta;
                            this.destination.x_d = this.cells[this.cellIndex].x_cell + this.flag_x * this.legacyHeight;
                            this.destination.y_d = this.cells[this.cellIndex].y_cell + this.flag_y * this.legacyHeight;
                            if (Math.abs(this.destination.x_d - this.cells[this.cellIndex + 1].x_cell) > this.Speed * Math.abs(this.flag_x) || Math.abs(this.destination.y_d - this.cells[this.cellIndex + 1].y_cell) > this.Speed * Math.abs(this.flag_y)) {
                                this.legacyHeight = -1;
                                this.destination.x_d += this.flag_x * this.Speed;
                                this.destination.y_d += this.flag_y * this.Speed;
                            }
                            else {
                                if (this.flag_x == 0) {
                                    this.legacyHeight = this.Speed - Math.abs(this.destination.y_d - this.cells[this.cellIndex + 1].y_cell) / Math.abs(this.flag_y);
                                }
                                else {
                                    this.legacyHeight = this.Speed - Math.abs(this.destination.x_d - this.cells[this.cellIndex + 1].x_cell) / Math.abs(this.flag_x);
                                }
                            }
                        }
                    }
                    else {
                        this.destination.x_d += this.flag_x * this.Speed;
                        this.destination.y_d += this.flag_y * this.Speed;
                        if (Math.abs(this.destination.x_d - this.cells[this.cellIndex + 1].x_cell) >= this.Speed * Math.abs(this.flag_x) && Math.abs(this.destination.y_d - this.cells[this.cellIndex + 1].y_cell) >= this.Speed * Math.abs(this.flag_y)) {
                            this.legacyHeight = -1;
                        }
                        else {
                            if (this.flag_x == 0) {
                                this.legacyHeight = this.Speed - Math.abs(this.destination.y_d - this.cells[this.cellIndex + 1].y_cell) / Math.abs(this.flag_y);
                            }
                            else {
                                this.legacyHeight = this.Speed - Math.abs(this.destination.x_d - this.cells[this.cellIndex + 1].x_cell) / Math.abs(this.flag_x);
                            }

                        }
                    }
                }else{
                    this.full=1;
                }
                this.deta_x = this.cells[1].x_cell - this.cells[0].x_cell;
                this.deta_y = this.cells[1].y_cell - this.cells[0].y_cell;
                this.deta = Math.sqrt(this.deta_x * this.deta_x + this.deta_y * this.deta_y);
                this.flag_x = this.deta_x / this.deta;
                this.flag_y = this.deta_y / this.deta;
                if (this.paused == 1) {
                    if (Math.abs(this.firstX - this.cells[0].x_cell) >= this.LineHeight * Math.abs(this.flag_x) && Math.abs(this.firstY - this.cells[0].y_cell) >= this.LineHeight * Math.abs(this.flag_y)) {
                        this.firstX = this.cells[0].x_cell;
                        this.firstY = this.cells[0].y_cell;
                        this.beginHeight = 0;
                    }
                    else {
                        if (this.beginHeight < this.LineHeight) {
                            if (this.beginHeight + this.Speed >= this.LineHeight) {
                                this.beginHeight = this.LineHeight;
                            }
                            else {
                                this.beginHeight += this.Speed;
                            }
                            this.firstX = this.cells[0].x_cell;
                            this.firstY = this.cells[0].y_cell;
                        }
                        else if (this.beginHeight == this.LineHeight) {
                            this.firstX += this.flag_x * this.Speed;
                            this.firstY += this.flag_y * this.Speed;
                        }
                    }
                }
            }

        }

draw函数

//draw函数在每次advance之后执行,将每次的步进更新重新绘制到画布上
 draw: function () {
            var canvas = this.core.canvas;            this.x_now = this.firstX;            this.y_now = this.firstY;            this.deta_x = this.cells[1].x_cell - this.cells[0].x_cell;            this.deta_y = this.cells[1].y_cell - this.cells[0].y_cell;            this.deta = Math.sqrt(this.deta_x * this.deta_x + this.deta_y * this.deta_y);            var myEnd = false;            this.flag_x = this.deta_x / this.deta;            this.flag_y = this.deta_y / this.deta;

            canvas.beginPath();
            canvas.lineJoin = 'round';
            canvas.lineCap="round";            this.endHeight = 0;
            canvas.lineWidth = this.GDwidth / 4;
            canvas.strokeStyle = this.fill;            if (this.beginHeight > 0) {
                canvas.moveTo(this.x_now, this.y_now);
                canvas.lineTo(this.x_now + this.flag_x * this.beginHeight, this.y_now + this.flag_y * this.beginHeight);
            }            this.x_now += this.flag_x * (this.beginHeight + this.LineHeight);            this.y_now += this.flag_y * (this.beginHeight + this.LineHeight);            for (var i = 1; i <= this.cellIndex; i++) {
                myEnd = false;                this.deta_x = this.cells[i].x_cell - this.cells[i - 1].x_cell;                this.deta_y = this.cells[i].y_cell - this.cells[i - 1].y_cell;                this.deta = Math.sqrt(this.deta_x * this.deta_x + this.deta_y * this.deta_y);                this.flag_x = this.deta_x / this.deta;                this.flag_y = this.deta_y / this.deta;                if (this.endHeight > 0) {
                    canvas.moveTo(this.cells[i - 1].x_cell, this.cells[i - 1].y_cell);
                    canvas.lineTo(this.cells[i - 1].x_cell + this.flag_x * (this.endHeight ), this.cells[i - 1].y_cell + this.flag_y * this.endHeight);                    this.x_now = this.cells[i - 1].x_cell + this.flag_x * (this.LineHeight + this.endHeight);                    this.y_now = this.cells[i - 1].y_cell + this.flag_y * (this.LineHeight + this.endHeight);
                }                if (this.endHeight < 0) {                    this.endHeight = Math.abs(this.endHeight);                    this.x_now = this.cells[i - 1].x_cell + this.flag_x * (this.endHeight);                    this.y_now = this.cells[i - 1].y_cell + this.flag_y * (this.endHeight);
                }                if (this.endHeight == 0 && i != 1) {                    this.x_now = this.cells[i - 1].x_cell;                    this.y_now = this.cells[i - 1].y_cell;
                }                while (Math.abs(this.x_now - this.cells[i].x_cell) >= this.LineHeight * Math.abs(this.flag_x) && Math.abs(this.y_now - this.cells[i].y_cell) >= this.LineHeight * Math.abs(this.flag_y)) {
                    canvas.moveTo(this.x_now, this.y_now);
                    canvas.lineTo(this.x_now + this.flag_x * this.LineHeight, this.y_now + this.flag_y * this.LineHeight);                    this.x_now += this.flag_x * this.LineHeight;                    this.y_now += this.flag_y * this.LineHeight;                    if (Math.abs(this.x_now - this.cells[i].x_cell) <= this.LineHeight * Math.abs(this.flag_x) && Math.abs(this.y_now - this.cells[i].y_cell) <= this.LineHeight * Math.abs(this.flag_y)) {                        if (this.flag_x == 0) {                            this.endHeight = Math.abs(this.y_now - this.cells[i].y_cell) / Math.abs(this.flag_y) - this.LineHeight;
                        }                        else {                            this.endHeight = Math.abs(this.x_now - this.cells[i].x_cell) / Math.abs(this.flag_x) - this.LineHeight;
                        }                        //this.endHeight = (Math.abs(this.y_now - this.cells[i].y_cell) + Math.abs(this.x_now - this.cells[i].x_cell) - this.LineHeight * (Math.abs(this.flag_y) + Math.abs(this.flag_x)))/2;
                        myEnd = true;                        break;
                    }                    else {                        this.x_now += this.flag_x * this.LineHeight;                        this.y_now += this.flag_y * this.LineHeight;
                    }
                }                if (myEnd == false && Math.abs(this.x_now - this.cells[i].x_cell) <= this.LineHeight * Math.abs(this.flag_x) && Math.abs(this.y_now - this.cells[i].y_cell) <= this.LineHeight * Math.abs(this.flag_y)) {
                    canvas.moveTo(this.x_now, this.y_now);
                    canvas.lineTo(this.cells[i].x_cell, this.cells[i].y_cell);                    //this.endHeight = this.LineHeight - Math.abs(this.x_now - this.cells[i].x_cell)*flag.x_flag - Math.abs(this.y_now - this.cells[i].y_cell)*flag.y_flag;
                    if (this.flag_x == 0) {                        this.endHeight = this.LineHeight - Math.abs(this.y_now - this.cells[i].y_cell) / Math.abs(this.flag_y);
                    }                    else {                        this.endHeight = this.LineHeight - Math.abs(this.x_now - this.cells[i].x_cell) / Math.abs(this.flag_x);
                    }                    //this.endHeight = ( this.LineHeight * (Math.abs(this.flag_y) + Math.abs(this.flag_x)) - Math.abs(this.y_now - this.cells[i].y_cell) + Math.abs(this.x_now - this.cells[i].x_cell)) / 2;
                }
            }            if (this.cellIndex < this.cells.length - 1) {

                myEnd = false;                this.deta_x = this.cells[this.cellIndex+1].x_cell-this.destination.x_d;                this.deta_y = this.cells[this.cellIndex+1].y_cell-this.destination.y_d;                this.deta = Math.sqrt(this.deta_x * this.deta_x + this.deta_y * this.deta_y);                if (this.deta > 0) {                    this.flag_x = this.deta_x / this.deta;                    this.flag_y = this.deta_y / this.deta;                    if (this.endHeight > 0) {
                        canvas.moveTo(this.cells[this.cellIndex].x_cell, this.cells[this.cellIndex].y_cell);
                        canvas.lineTo(this.cells[this.cellIndex].x_cell + this.flag_x * (this.endHeight ), this.cells[this.cellIndex].y_cell + this.flag_y * this.endHeight);                        this.x_now = this.cells[this.cellIndex].x_cell + this.flag_x * ( this.endHeight);                        this.y_now = this.cells[this.cellIndex].y_cell + this.flag_y * ( this.endHeight);                        if(Math.abs(this.destination.x_d-this.x_now)>this.LineHeight*Math.abs(this.flag_x)||Math.abs(this.destination.y_d-this.y_now)>this.LineHeight*Math.abs(this.flag_y)){                            this.x_now+=this.LineHeight*this.flag_x;                            this.y_now+=this.LineHeight*this.flag_y;
                        }                        else{                            this.x_now=this.destination.x_d;                            this.y_now=this.destination.y_d;
                        }                    if (this.endHeight < 0) {                        this.endHeight = Math.abs(this.endHeight);                        this.x_now = this.cells[this.cellIndex].x_cell + this.flag_x * (this.endHeight);                        this.y_now = this.cells[this.cellIndex].y_cell + this.flag_y * (this.endHeight);
                    }                    if (this.endHeight == 0 && this.cellIndex > 0) {                        this.x_now = this.cells[this.cellIndex].x_cell;                        this.y_now = this.cells[this.cellIndex].y_cell;
                    }                    if (this.cellIndex == 0) {                        this.x_now = this.firstX;                        this.y_now = this.firstY;                        if (this.beginHeight > 0) {
                            canvas.moveTo(this.x_now, this.y_now);
                            canvas.lineTo(this.x_now + this.flag_x * this.beginHeight, this.y_now + this.flag_y * this.beginHeight);
                        }                        this.x_now += this.flag_x * (this.beginHeight + this.LineHeight);                        this.y_now += this.flag_y * (this.beginHeight + this.LineHeight);
                    }                    while ((Math.abs(this.x_now - this.destination.x_d) >= this.LineHeight * Math.abs(this.flag_x) && Math.abs(this.y_now - this.destination.y_d) >this.LineHeight * Math.abs(this.flag_y))||(Math.abs(this.x_now - this.destination.x_d) > this.LineHeight * Math.abs(this.flag_x) && Math.abs(this.y_now - this.destination.y_d) >=this.LineHeight * Math.abs(this.flag_y))) {
                        canvas.moveTo(this.x_now, this.y_now);
                        canvas.lineTo(this.x_now + this.flag_x * this.LineHeight, this.y_now + this.flag_y * this.LineHeight);                        this.x_now += this.flag_x * this.LineHeight;                        this.y_now += this.flag_y * this.LineHeight;                        if (Math.abs(this.x_now - this.destination.x_d)<= this.LineHeight * Math.abs(this.flag_x)&&Math.abs(this.y_now - this.destination.y_d) <= this.LineHeight * Math.abs(this.flag_y)) {
                            myEnd = true;                            break;
                        }                        else {                            this.x_now += this.flag_x * this.LineHeight;                            this.y_now += this.flag_y * this.LineHeight;
                        }
                    }                    if (myEnd == false && Math.abs(this.x_now - this.destination.x_d) < this.LineHeight * Math.abs(this.flag_x) || Math.abs(this.y_now - this.destination.y_d) < this.LineHeight * Math.abs(this.flag_y)) {
                        canvas.moveTo(this.x_now, this.y_now);
                        canvas.lineTo(this.destination.x_d, this.destination.y_d);
                    }
                }
            }
            canvas.stroke();
            canvas.closePath();
        }

 取水泵房的实例

下面代码在定义了一个水池对象,并赋予了相应的属性值,最后将定义的对象添加到canvas画布中。

笔目鱼英文论文写作器
笔目鱼英文论文写作器

写高质量英文论文,就用笔目鱼

下载
var SC01 = canvas.display.SC_show({        x: 326,        y: 200,
        Width: 181,
        Height: 438,
        height_now: 0,
        trail_flag: 0,
        t: 0,
        fill: color_SC,
        speed:speed_SC,
        full:0,
        start:0
    });canvas.addChild(SC01);

下面的代码定义了一个管道对象,并且给管道对象赋予了一些初始值,最后添加到canvas画布中。

var GD01 = canvas.display.GD({        x: 0,        y: 0,
        destination: {
            x_d: 0, y_d: 0
        },
        cells: [
            {x_cell: 195, y_cell: 587},
            {x_cell: 335, y_cell: 587}
        ],
        deta: 1,
        deta_x: 1,
        deta_y: 0,
        flag_x: 1,
        flag_y: 0,
        cellIndex: 0,        
        Speed: speed_all,     
        GDwidth: width_all,     
        LineHeight: 10,     
        x_now: 0,      
        y_now: 0,       
        firstX: 0,     
        firstY: 0,      
        beginHeight: 0,    
        endHeight: 0,     
        legacyHeight: 0,
        paused: 1,
        fill:color_GD,
        full:0
    });
 canvas.addChild(GD01);

具体动画的流程控制如下:

 canvas.setLoop(function () {
        //下面6个advance函数实现每一帧中的动画对象的更新操作
        GD01.advance();
        SC01.advance();
        SC02.advance();
        GD02.advance();
        SC03.advance();
        GD03.advance();
        //下面几个if语句实现动画的流程控制
        if(GD01.full==1){
            SC01.start = 1;
            SC02.start = 1;
        }
        if(SC02.full==1){
            GD02.paused = 1;
        }
        if(GD02.full==1) {
            SC03.start = 1;
            arrow_1.start();
            arrow_2.start();
        }
        if(SC03.full==1) {
            GD03.paused = 1;
        }
        canvas.redraw();  //重绘画布
    }).start();       //循环开始

【相关推荐】

1. 特别推荐“php程序员工具箱”V0.1版本下载

2. h5canvas实现雪花飘落的特效代码

3. h5 Canvas中Fill 与Stroke文字效果实现实例

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

463

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

135

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

64

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

20

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

26

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

14

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

524

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

53

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Canvas 绘制时钟
Canvas 绘制时钟

共7课时 | 1.6万人学习

HTML5新特性基础视频教程
HTML5新特性基础视频教程

共18课时 | 3.3万人学习

HTML5 Canvas 动画实战教程
HTML5 Canvas 动画实战教程

共28课时 | 6.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号