HTAML双层爱心

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <title></title>

  </head>

  <body>

    <!-- 绘画爱心 -->

    <canvas id="canvas" width="1400" height="600"></canvas>

    <!-- js部分 -->

<style>

    * {

        padding: 0;

        margin: 0;

    }

    html,

    body {

        height: 100%;

        padding: 0;

        margin: 0;

        background: #000;

    }

    .aa {

        position: fixed;

        left: 50%;

        bottom: 10px;

        color: #ccc;

    }

    .container {

        width: 100%;

        height: 100%;

    }

    canvas {

        z-index: 99;

        position: absolute;

        width: 100%;

        height: 100%;

    }

</style>

<body>

 <!-- 爱心 -->

    <canvas id="pinkboard" class="container"> </canvas>

<script>

    /*

     * 设置的

     */

    var settings = {

        particles: {

            length: 500, // 最大颗粒量

            duration: 2, // 粒子持续时间多少秒

            velocity: 100, // 粒子速度以像素/秒为单位

            effect: -0.75, // 玩这个以获得很好的效果

            size: 30, // 像素

        },

    };

    (function () {

        var b = 0;

        var c = ["ms", "moz", "webkit", "o"];

        for (var a = 0; a < c.length && !window.requestAnimationFrame; ++a) {

            window.requestAnimationFrame = window[c[a] + "RequestAnimationFrame"];

            window.cancelAnimationFrame =

                window[c[a] + "CancelAnimationFrame"] ||

                window[c[a] + "CancelRequestAnimationFrame"];

        }

        if (!window.requestAnimationFrame) {

            window.requestAnimationFrame = function (h, e) {

                var d = new Date().getTime();

                var f = Math.max(0, 16 - (d - b));

                var g = window.setTimeout(function () {

                    h(d + f);

                }, f);

                b = d + f;

                return g;

            };

        }

        if (!window.cancelAnimationFrame) {

            window.cancelAnimationFrame = function (d) {

                clearTimeout(d);

            };

        }

    })();

    /*

     *点类

     */

    var Point = (function () {

        function Point(x, y) {

            this.x = typeof x !== "undefined" ? x : 0;

            this.y = typeof y !== "undefined" ? y : 0;

        }

        Point.prototype.clone = function () {

            return new Point(this.x, this.y);

        };

        Point.prototype.length = function (length) {

            if (typeof length == "undefined")

                return Math.sqrt(this.x * this.x + this.y * this.y);

            this.normalize();

            this.x *= length;

            this.y *= length;

            return this;

        };

        Point.prototype.normalize = function () {

            var length = this.length();

            this.x /= length;

            this.y /= length;

            return this;

        };

        return Point;

    })();

    /*

     * 粒子类

     */

    var Particle = (function () {

        function Particle() {

            this.position = new Point();

            this.velocity = new Point();

            this.acceleration = new Point();

            this.age = 0;

        }

        Particle.prototype.initialize = function (x, y, dx, dy) {

            this.position.x = x;

            this.position.y = y;

            this.velocity.x = dx;

            this.velocity.y = dy;

            this.acceleration.x = dx * settings.particles.effect;

            this.acceleration.y = dy * settings.particles.effect;

            this.age = 0;

        };

        Particle.prototype.update = function (deltaTime) {

            this.position.x += this.velocity.x * deltaTime;

            this.position.y += this.velocity.y * deltaTime;

            this.velocity.x += this.acceleration.x * deltaTime;

            this.velocity.y += this.acceleration.y * deltaTime;

            this.age += deltaTime;

        };

        Particle.prototype.draw = function (context, image) {

            function ease(t) {

                return --t * t * t + 1;

            }

            var size = image.width * ease(this.age / settings.particles.duration);

            context.globalAlpha = 1 - this.age / settings.particles.duration;

            context.drawImage(

                image,

                this.position.x - size / 2,

                this.position.y - size / 2,

                size,

                size

            );

        };

        return Particle;

    })();

    /*

        *粒子池类

        */

    var ParticlePool = (function () {

        var particles,

            firstActive = 0,

            firstFree = 0,

            duration = settings.particles.duration;

        function ParticlePool(length) {

            // 创建并填充粒子池

            particles = new Array(length);

            for (var i = 0; i < particles.length; i++)

                particles[i] = new Particle();

        }

        ParticlePool.prototype.add = function (x, y, dx, dy) {

            particles[firstFree].initialize(x, y, dx, dy);

            // 处理循环队列

            firstFree++;

            if (firstFree == particles.length) firstFree = 0;

            if (firstActive == firstFree) firstActive++;

            if (firstActive == particles.length) firstActive = 0;

        };

        ParticlePool.prototype.update = function (deltaTime) {

            var i;

            // 更新活性粒子

            if (firstActive < firstFree) {

                for (i = firstActive; i < firstFree; i++)

                    particles[i].update(deltaTime);

            }

            if (firstFree < firstActive) {

                for (i = firstActive; i < particles.length; i++)

                    particles[i].update(deltaTime);

                for (i = 0; i < firstFree; i++) particles[i].update(deltaTime);

            }


 

            // 去除非活性颗粒

            while (

                particles[firstActive].age >= duration &&

                firstActive != firstFree

            ) {

                firstActive++;

                if (firstActive == particles.length) firstActive = 0;

            }

        };

        ParticlePool.prototype.draw = function (context, image) {

            // 绘制活性粒子

            if (firstActive < firstFree) {

                for (i = firstActive; i < firstFree; i++)

                    particles[i].draw(context, image);

            }

            if (firstFree < firstActive) {

                for (i = firstActive; i < particles.length; i++)

                    particles[i].draw(context, image);

                for (i = 0; i < firstFree; i++) particles[i].draw(context, image);

            }

        };

        return ParticlePool;

    })();

    /*

      * 将一切整合在一起

      */

    (function (canvas) {

        var context = canvas.getContext("2d"),

            particles = new ParticlePool(settings.particles.length),

            particleRate =

                settings.particles.length / settings.particles.duration, // 粒子多少秒

            time;


 

        // 用 -PI <= t <= PI 获得心脏点

        function pointOnHeart(t) {

            return new Point(

                160 * Math.pow(Math.sin(t), 3),

                130 * Math.cos(t) -

                50 * Math.cos(2 * t) -

                20 * Math.cos(3 * t) -

                10 * Math.cos(4 * t) +

                25

            );

        }

        // 使用虚拟画布创建粒子图像

        var image = (function () {

            var canvas = document.createElement("canvas"),

                context = canvas.getContext("2d");

            canvas.width = settings.particles.size;

            canvas.height = settings.particles.size;

            // 用于创建路径的帮助程序函数

            function to(t) {

                var point = pointOnHeart(t);

                point.x =

                    settings.particles.size / 2 +

                    (point.x * settings.particles.size) / 350;

                point.y =

                    settings.particles.size / 2 -

                    (point.y * settings.particles.size) / 350;

                return point;

            }

            // 创建路径

            context.beginPath();

            var t = -Math.PI;

            var point = to(t);

            context.moveTo(point.x, point.y);

            while (t < Math.PI) {

                t += 0.01; // 婴儿步骤

                point = to(t);

                context.lineTo(point.x, point.y);

            }

            context.closePath();

            // 创建填充

            context.fillStyle = "#ea80b0";

            context.fill();

            // 创建映像

            var image = new Image();

            image.src = canvas.toDataURL();

            return image;

        })();

        // 渲染那个东西

        function render() {

            //下一个动画帧

            requestAnimationFrame(render);

            // 更新时间

            var newTime = new Date().getTime() / 1000,

                deltaTime = newTime - (time || newTime);

            time = newTime;

            // 透明画布

            context.clearRect(0, 0, canvas.width, canvas.height);

            //创建新粒子

            var amount = particleRate * deltaTime;

            for (var i = 0; i < amount; i++) {

                var pos = pointOnHeart(Math.PI - 2 * Math.PI * Math.random());

                var dir = pos.clone().length(settings.particles.velocity);

                particles.add(

                    canvas.width / 2 + pos.x,

                    canvas.height / 2 - pos.y,

                    dir.x,

                    -dir.y

                );

            }

            //更新和绘制粒子

            particles.update(deltaTime);

            particles.draw(context, image);

        }

        // 处理重新调整画布的大小

        function onResize() {

            canvas.width = canvas.clientWidth;

            canvas.height = canvas.clientHeight;

        }

        window.onresize = onResize;

        // 延迟渲染引导

        setTimeout(function () {

            onResize();

            render();

        }, 10);

    })(document.getElementById("pinkboard"));

</script>

var canvas = document.getElementById("canvas");

canvas.width = window.innerWidth;

canvas.height = window.innerHeight;

// Initialize the GL context

var gl = canvas.getContext('webgl');

if (!gl) {

    console.error("Unable to initialize WebGL.");

}

//Time step

var dt = 0.015;

//Time

var time = 0.0;

//************** Shader sources **************

var vertexSource = `

attribute vec2 position;

void main() {

    gl_Position = vec4(position, 0.0, 1.0);

}

`;

var fragmentSource = `

precision highp float;

uniform float width;

uniform float height;

vec2 resolution = vec2(width, height);

uniform float time;

#define POINT_COUNT 8

vec2 points[POINT_COUNT];

const float speed = -0.5;

const float len = 0.25;

float intensity = 0.9;

float radius = 0.015;

//https://www.shadertoy.com/view/MlKcDD

//Signed distance to a quadratic bezier

float sdBezier(vec2 pos, vec2 A, vec2 B, vec2 C){    

    vec2 a = B - A;

    vec2 b = A - 2.0*B + C;

    vec2 c = a * 2.0;

    vec2 d = A - pos;

    float kk = 1.0 / dot(b,b);

    float kx = kk * dot(a,b);

    float ky = kk * (2.0*dot(a,a)+dot(d,b)) / 3.0;

    float kz = kk * dot(d,a);      

    float res = 0.0;

    float p = ky - kx*kx;

    float p3 = p*p*p;

    float q = kx*(2.0*kx*kx - 3.0*ky) + kz;

    float h = q*q + 4.0*p3;

    if(h >= 0.0){

        h = sqrt(h);

        vec2 x = (vec2(h, -h) - q) / 2.0;

        vec2 uv = sign(x)*pow(abs(x), vec2(1.0/3.0));

        float t = uv.x + uv.y - kx;

        t = clamp( t, 0.0, 1.0 );

        // 1 root

        vec2 qos = d + (c + b*t)*t;

        res = length(qos);

    }else{

        float z = sqrt(-p);

        float v = acos( q/(p*z*2.0) ) / 3.0;

        float m = cos(v);

        float n = sin(v)*1.732050808;

        vec3 t = vec3(m + m, -n - m, n - m) * z - kx;

        t = clamp( t, 0.0, 1.0 );

        // 3 roots

        vec2 qos = d + (c + b*t.x)*t.x;

        float dis = dot(qos,qos);

        res = dis;

        qos = d + (c + b*t.y)*t.y;

        dis = dot(qos,qos);

        res = min(res,dis);

        qos = d + (c + b*t.z)*t.z;

        dis = dot(qos,qos);

        res = min(res,dis);

        res = sqrt( res );

    }

    return res;

}


 

//http://mathworld.wolfram.com/HeartCurve.html

vec2 getHeartPosition(float t){

    return vec2(16.0 * sin(t) * sin(t) * sin(t),

                            -(13.0 * cos(t) - 5.0 * cos(2.0*t)

                            - 2.0 * cos(3.0*t) - cos(4.0*t)));

}

//https://www.shadertoy.com/view/3s3GDn

float getGlow(float dist, float radius, float intensity){

    return pow(radius/dist, intensity);

}

float getSegment(float t, vec2 pos, float offset, float scale){

    for(int i = 0; i < POINT_COUNT; i++){

        points[i] = getHeartPosition(offset + float(i)*len + fract(speed * t) * 6.28);

    }

    vec2 c = (points[0] + points[1]) / 2.0;

    vec2 c_prev;

    float dist = 10000.0;

    for(int i = 0; i < POINT_COUNT-1; i++){

        //https://tinyurl.com/y2htbwkm

        c_prev = c;

        c = (points[i] + points[i+1]) / 2.0;

        dist = min(dist, sdBezier(pos, scale * c_prev, scale * points[i], scale * c));

    }

    return max(0.0, dist);

}

void main(){

    vec2 uv = gl_FragCoord.xy/resolution.xy;

    float widthHeightRatio = resolution.x/resolution.y;

    vec2 centre = vec2(0.5, 0.5);

    vec2 pos = centre - uv;

    pos.y /= widthHeightRatio;

    //Shift upwards to centre heart

    pos.y += 0.02;

    float scale = 0.000015 * height;

    float t = time;

    //Get first segment

    float dist = getSegment(t, pos, 0.0, scale);

    float glow = getGlow(dist, radius, intensity);

    vec3 col = vec3(0.0);

    //White core

    col += 10.0*vec3(smoothstep(0.003, 0.001, dist));

    //Pink glow

    col += glow * vec3(0.94,0.14,0.4);

    //Get second segment

    dist = getSegment(t, pos, 3.4, scale);

    glow = getGlow(dist, radius, intensity);

    //White core

    col += 10.0*vec3(smoothstep(0.003, 0.001, dist));

    //Blue glow

    col += glow * vec3(0.2,0.6,1.0);

    //Tone mapping

    col = 1.0 - exp(-col);

    //Output to screen

    gl_FragColor = vec4(col,1.0);

}

`;

//************** Utility functions **************

window.addEventListener('resize', onWindowResize, false);

function onWindowResize() {

    canvas.width = window.innerWidth;

    canvas.height = window.innerHeight;

    gl.viewport(0, 0, canvas.width, canvas.height);

    gl.uniform1f(widthHandle, window.innerWidth);

    gl.uniform1f(heightHandle, window.innerHeight);

}


 

//Compile shader and combine with source

function compileShader(shaderSource, shaderType) {

    var shader = gl.createShader(shaderType);

    gl.shaderSource(shader, shaderSource);

    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

        throw "Shader compile failed with: " + gl.getShaderInfoLog(shader);

    }

    return shader;

}

//From https://codepen.io/jlfwong/pen/GqmroZ

//Utility to complain loudly if we fail to find the attribute/uniform

function getAttribLocation(program, name) {

    var attributeLocation = gl.getAttribLocation(program, name);

    if (attributeLocation === -1) {

        throw 'Cannot find attribute ' + name + '.';

    }

    return attributeLocation;

}

function getUniformLocation(program, name) {

    var attributeLocation = gl.getUniformLocation(program, name);

    if (attributeLocation === -1) {

        throw 'Cannot find uniform ' + name + '.';

    }

    return attributeLocation;

}

//************** Create shaders **************

//Create vertex and fragment shaders

var vertexShader = compileShader(vertexSource, gl.VERTEX_SHADER);

var fragmentShader = compileShader(fragmentSource, gl.FRAGMENT_SHADER);

//Create shader programs

var program = gl.createProgram();

gl.attachShader(program, vertexShader);

gl.attachShader(program, fragmentShader);

gl.linkProgram(program);

gl.useProgram(program);

//Set up rectangle covering entire canvas

var vertexData = new Float32Array([-1.0, 1.0, // top left

    -1.0, -1.0, // bottom left

    1.0, 1.0, // top right

    1.0, -1.0, // bottom right

]);

//Create vertex buffer

var vertexDataBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer);

gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);

// Layout of our data in the vertex buffer

var positionHandle = getAttribLocation(program, 'position');

gl.enableVertexAttribArray(positionHandle);

gl.vertexAttribPointer(positionHandle,

    2, // position is a vec2 (2 values per component)

    gl.FLOAT, // each component is a float

    false, // don't normalize values

    2 * 4, // two 4 byte float components per vertex (32 bit float is 4 bytes)

    0 // how many bytes inside the buffer to start from

);

//Set uniform handle

var timeHandle = getUniformLocation(program, 'time');

var widthHandle = getUniformLocation(program, 'width');

var heightHandle = getUniformLocation(program, 'height');

gl.uniform1f(widthHandle, window.innerWidth);

gl.uniform1f(heightHandle, window.innerHeight);

function draw() {

    //Update time

    time += dt;

    //Send uniforms to program

    gl.uniform1f(timeHandle, time);

    //Draw a triangle strip connecting vertices 0-4

    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

    requestAnimationFrame(draw);

}

draw();

<script>

    var canvas = document.getElementById("canvas");

canvas.width = window.innerWidth;

canvas.height = window.innerHeight;

// Initialize the GL context

var gl = canvas.getContext('webgl');

if (!gl) {

    console.error("Unable to initialize WebGL.");

}

//Time step

var dt = 0.015;

//Time

var time = 0.0;

//************** Shader sources **************

var vertexSource = `

attribute vec2 position;

void main() {

    gl_Position = vec4(position, 0.0, 1.0);

}

`;

var fragmentSource = `

precision highp float;

uniform float width;

uniform float height;

vec2 resolution = vec2(width, height);

uniform float time;

#define POINT_COUNT 8

vec2 points[POINT_COUNT];

const float speed = -0.5;

const float len = 0.25;

float intensity = 0.9;

float radius = 0.015;

//https://www.shadertoy.com/view/MlKcDD

//Signed distance to a quadratic bezier

float sdBezier(vec2 pos, vec2 A, vec2 B, vec2 C){    

    vec2 a = B - A;

    vec2 b = A - 2.0*B + C;

    vec2 c = a * 2.0;

    vec2 d = A - pos;

    float kk = 1.0 / dot(b,b);

    float kx = kk * dot(a,b);

    float ky = kk * (2.0*dot(a,a)+dot(d,b)) / 3.0;

    float kz = kk * dot(d,a);      

    float res = 0.0;

    float p = ky - kx*kx;

    float p3 = p*p*p;

    float q = kx*(2.0*kx*kx - 3.0*ky) + kz;

    float h = q*q + 4.0*p3;

    if(h >= 0.0){

        h = sqrt(h);

        vec2 x = (vec2(h, -h) - q) / 2.0;

        vec2 uv = sign(x)*pow(abs(x), vec2(1.0/3.0));

        float t = uv.x + uv.y - kx;

        t = clamp( t, 0.0, 1.0 );

        // 1 root

        vec2 qos = d + (c + b*t)*t;

        res = length(qos);

    }else{

        float z = sqrt(-p);

        float v = acos( q/(p*z*2.0) ) / 3.0;

        float m = cos(v);

        float n = sin(v)*1.732050808;

        vec3 t = vec3(m + m, -n - m, n - m) * z - kx;

        t = clamp( t, 0.0, 1.0 );

        // 3 roots

        vec2 qos = d + (c + b*t.x)*t.x;

        float dis = dot(qos,qos);

        res = dis;

        qos = d + (c + b*t.y)*t.y;

        dis = dot(qos,qos);

        res = min(res,dis);

        qos = d + (c + b*t.z)*t.z;

        dis = dot(qos,qos);

        res = min(res,dis);

        res = sqrt( res );

    }

    return res;

}

//http://mathworld.wolfram.com/HeartCurve.html

vec2 getHeartPosition(float t){

    return vec2(16.0 * sin(t) * sin(t) * sin(t),

                            -(13.0 * cos(t) - 5.0 * cos(2.0*t)

                            - 2.0 * cos(3.0*t) - cos(4.0*t)));

}

//https://www.shadertoy.com/view/3s3GDn

float getGlow(float dist, float radius, float intensity){

    return pow(radius/dist, intensity);

}

float getSegment(float t, vec2 pos, float offset, float scale){

    for(int i = 0; i < POINT_COUNT; i++){

        points[i] = getHeartPosition(offset + float(i)*len + fract(speed * t) * 6.28);

    }

    vec2 c = (points[0] + points[1]) / 2.0;

    vec2 c_prev;

    float dist = 10000.0;

    for(int i = 0; i < POINT_COUNT-1; i++){

        //https://tinyurl.com/y2htbwkm

        c_prev = c;

        c = (points[i] + points[i+1]) / 2.0;

        dist = min(dist, sdBezier(pos, scale * c_prev, scale * points[i], scale * c));

    }

    return max(0.0, dist);

}

void main(){

    vec2 uv = gl_FragCoord.xy/resolution.xy;

    float widthHeightRatio = resolution.x/resolution.y;

    vec2 centre = vec2(0.5, 0.5);

    vec2 pos = centre - uv;

    pos.y /= widthHeightRatio;

    //Shift upwards to centre heart

    pos.y += 0.02;

    float scale = 0.000015 * height;

    float t = time;

    //Get first segment

    float dist = getSegment(t, pos, 0.0, scale);

    float glow = getGlow(dist, radius, intensity);

    vec3 col = vec3(0.0);

    //White core

    col += 10.0*vec3(smoothstep(0.003, 0.001, dist));

    //Pink glow

    col += glow * vec3(0.94,0.14,0.4);

    //Get second segment

    dist = getSegment(t, pos, 3.4, scale);

    glow = getGlow(dist, radius, intensity);

    //White core

    col += 10.0*vec3(smoothstep(0.003, 0.001, dist));

    //Blue glow

    col += glow * vec3(0.2,0.6,1.0);

    //Tone mapping

    col = 1.0 - exp(-col);

    //Output to screen

    gl_FragColor = vec4(col,1.0);

}

`;

//************** Utility functions **************

window.addEventListener('resize', onWindowResize, false);

function onWindowResize() {

    canvas.width = window.innerWidth;

    canvas.height = window.innerHeight;

    gl.viewport(0, 0, canvas.width, canvas.height);

    gl.uniform1f(widthHandle, window.innerWidth);

    gl.uniform1f(heightHandle, window.innerHeight);

}

//Compile shader and combine with source

function compileShader(shaderSource, shaderType) {

    var shader = gl.createShader(shaderType);

    gl.shaderSource(shader, shaderSource);

    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

        throw "Shader compile failed with: " + gl.getShaderInfoLog(shader);

    }

    return shader;

}

//From https://codepen.io/jlfwong/pen/GqmroZ

//Utility to complain loudly if we fail to find the attribute/uniform

function getAttribLocation(program, name) {

    var attributeLocation = gl.getAttribLocation(program, name);

    if (attributeLocation === -1) {

        throw 'Cannot find attribute ' + name + '.';

    }

    return attributeLocation;

}

function getUniformLocation(program, name) {

    var attributeLocation = gl.getUniformLocation(program, name);

    if (attributeLocation === -1) {

        throw 'Cannot find uniform ' + name + '.';

    }

    return attributeLocation;

}

//************** Create shaders **************

//Create vertex and fragment shaders

var vertexShader = compileShader(vertexSource, gl.VERTEX_SHADER);

var fragmentShader = compileShader(fragmentSource, gl.FRAGMENT_SHADER);

//Create shader programs

var program = gl.createProgram();

gl.attachShader(program, vertexShader);

gl.attachShader(program, fragmentShader);

gl.linkProgram(program);

gl.useProgram(program);

//Set up rectangle covering entire canvas

var vertexData = new Float32Array([-1.0, 1.0, // top left

    -1.0, -1.0, // bottom left

    1.0, 1.0, // top right

    1.0, -1.0, // bottom right

]);

//Create vertex buffer

var vertexDataBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer);

gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);

// Layout of our data in the vertex buffer

var positionHandle = getAttribLocation(program, 'position');

gl.enableVertexAttribArray(positionHandle);

gl.vertexAttribPointer(positionHandle,

    2, // position is a vec2 (2 values per component)

    gl.FLOAT, // each component is a float

    false, // don't normalize values

    2 * 4, // two 4 byte float components per vertex (32 bit float is 4 bytes)

    0 // how many bytes inside the buffer to start from

);

//Set uniform handle

var timeHandle = getUniformLocation(program, 'time');

var widthHandle = getUniformLocation(program, 'width');

var heightHandle = getUniformLocation(program, 'height');

gl.uniform1f(widthHandle, window.innerWidth);

gl.uniform1f(heightHandle, window.innerHeight);

function draw() {

    //Update time

    time += dt;

    //Send uniforms to program

    gl.uniform1f(timeHandle, time);

    //Draw a triangle strip connecting vertices 0-4

    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

    requestAnimationFrame(draw);

}

draw();

</script>

  </body>

</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值