首頁

好看的圣誕樹(動態(tài)效果) 轉(zhuǎn)自 csdn

前端達(dá)人

、制作方法 

1.復(fù)制代碼到Dreamweaver或HBuilder或vscode中

2.點(diǎn)擊運(yùn)行---運(yùn)行到瀏覽器---選擇你要打開的瀏覽器

3.打開后會出現(xiàn)這個界面,前四個是固定音樂,最后一個是自主選擇的音樂,你可以選擇你電腦上的歌曲,什么歌曲都行(第一次打開可能會有點(diǎn)慢,稍等片刻即可,選擇音樂的時候點(diǎn)一下沒反應(yīng)的話多點(diǎn)幾下即可,第一次打開這屬于正?,F(xiàn)象)

 

4.特別提醒:打開的時候電腦一定要處于聯(lián)網(wǎng)狀態(tài)
 

三、源代碼

 
  1.  
    <!DOCTYPE html>
  2.  
    <html lang="en">
  3.  
     
  4.  
    <head>
  5.  
    <meta charset="UTF-8">
  6.  
     
  7.  
    <title>圣誕樹</title>
  8.  
     
  9.  
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
  10.  
     
  11.  
    <style>
  12.  
    * {
  13.  
    box-sizing: border-box;
  14.  
    }
  15.  
     
  16.  
     
  17.  
    body {
  18.  
    margin: 0;
  19.  
    height: 100vh;
  20.  
    overflow: hidden;
  21.  
    display: flex;
  22.  
    align-items: center;
  23.  
    justify-content: center;
  24.  
    background: #161616;
  25.  
    color: #c5a880;
  26.  
    font-family: sans-serif;
  27.  
    }
  28.  
     
  29.  
     
  30.  
    label {
  31.  
    display: inline-block;
  32.  
    background-color: #161616;
  33.  
    padding: 16px;
  34.  
    border-radius: 0.3rem;
  35.  
    cursor: pointer;
  36.  
    margin-top: 1rem;
  37.  
    width: 300px;
  38.  
    border-radius: 10px;
  39.  
    border: 1px solid #c5a880;
  40.  
    text-align: center;
  41.  
    }
  42.  
     
  43.  
     
  44.  
    ul {
  45.  
    list-style-type: none;
  46.  
    padding: 0;
  47.  
    margin: 0;
  48.  
    }
  49.  
     
  50.  
     
  51.  
    .btn {
  52.  
    background-color: #161616;
  53.  
    border-radius: 10px;
  54.  
    color: #c5a880;
  55.  
    border: 1px solid #c5a880;
  56.  
    padding: 16px;
  57.  
    width: 300px;
  58.  
    margin-bottom: 16px;
  59.  
    line-height: 1.5;
  60.  
    cursor: pointer;
  61.  
    }
  62.  
     
  63.  
    .separator {
  64.  
    font-weight: bold;
  65.  
    text-align: center;
  66.  
    width: 300px;
  67.  
    margin: 16px 0px;
  68.  
    color: #a07676;
  69.  
    }
  70.  
     
  71.  
     
  72.  
    .title {
  73.  
    color: #a07676;
  74.  
    font-weight: bold;
  75.  
    font-size: 1.25rem;
  76.  
    margin-bottom: 16px;
  77.  
    }
  78.  
     
  79.  
     
  80.  
    .text-loading {
  81.  
    font-size: 2rem;
  82.  
    }
  83.  
    </style>
  84.  
     
  85.  
    <script>
  86.  
    window.console = window.console || function (t) { };
  87.  
    </script>
  88.  
     
  89.  
     
  90.  
     
  91.  
    <script>
  92.  
    if (document.location.search.match(/type=embed/gi)) {
  93.  
    window.parent.postMessage("resize", "*");
  94.  
    }
  95.  
    </script>
  96.  
     
  97.  
     
  98.  
    </head>
  99.  
     
  100.  
    <body translate="no">
  101.  
    <script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script>
  102.  
    <script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/EffectComposer.js"></script>
  103.  
    <script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/RenderPass.js"></script>
  104.  
    <script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/ShaderPass.js"></script>
  105.  
    <script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/shaders/CopyShader.js"></script>
  106.  
    <script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/shaders/LuminosityHighPassShader.js"></script>
  107.  
    <script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/UnrealBloomPass.js"></script>
  108.  
     
  109.  
    <div id="overlay">
  110.  
    <ul>
  111.  
    <li class="title">請選擇音樂</li>
  112.  
    <li>
  113.  
    <button class="btn" id="btnA" type="button">
  114.  
    Snowflakes Falling Down by Simon Panrucker
  115.  
    </button>
  116.  
    </li>
  117.  
    <li><button class="btn" id="btnB" type="button">This Christmas by Dott</button></li>
  118.  
    <li><button class="btn" id="btnC" type="button">No room at the inn by TRG Banks</button></li>
  119.  
    <li><button class="btn" id="btnD" type="button">Jingle Bell Swing by Mark Smeby</button></li>
  120.  
    <li class="separator">或者</li>
  121.  
    <li>
  122.  
    <input type="file" id="upload" hidden />
  123.  
    <label for="upload">Upload File</label>
  124.  
    </li>
  125.  
    </ul>
  126.  
    </div>
  127.  
     
  128.  
    <script id="rendered-js">
  129.  
    const { PI, sin, cos } = Math;
  130.  
    const TAU = 2 * PI;
  131.  
     
  132.  
    const map = (value, sMin, sMax, dMin, dMax) => {
  133.  
    return dMin + (value - sMin) / (sMax - sMin) * (dMax - dMin);
  134.  
    };
  135.  
     
  136.  
    const range = (n, m = 0) =>
  137.  
    Array(n).
  138.  
    fill(m).
  139.  
    map((i, j) => i + j);
  140.  
     
  141.  
    const rand = (max, min = 0) => min + Math.random() * (max - min);
  142.  
    const randInt = (max, min = 0) => Math.floor(min + Math.random() * (max - min));
  143.  
    const randChoise = arr => arr[randInt(arr.length)];
  144.  
    const polar = (ang, r = 1) => [r * cos(ang), r * sin(ang)];
  145.  
     
  146.  
    let scene, camera, renderer, analyser;
  147.  
    let step = 0;
  148.  
    const uniforms = {
  149.  
    time: { type: "f", value: 0.0 },
  150.  
    step: { type: "f", value: 0.0 }
  151.  
    };
  152.  
     
  153.  
    const params = {
  154.  
    exposure: 1,
  155.  
    bloomStrength: 0.9,
  156.  
    bloomThreshold: 0,
  157.  
    bloomRadius: 0.5
  158.  
    };
  159.  
     
  160.  
    let composer;
  161.  
     
  162.  
    const fftSize = 2048;
  163.  
    const totalPoints = 4000;
  164.  
     
  165.  
    const listener = new THREE.AudioListener();
  166.  
     
  167.  
    const audio = new THREE.Audio(listener);
  168.  
     
  169.  
    document.querySelector("input").addEventListener("change", uploadAudio, false);
  170.  
     
  171.  
    const buttons = document.querySelectorAll(".btn");
  172.  
    buttons.forEach((button, index) =>
  173.  
    button.addEventListener("click", () => loadAudio(index)));
  174.  
     
  175.  
     
  176.  
    function init() {
  177.  
    const overlay = document.getElementById("overlay");
  178.  
    overlay.remove();
  179.  
     
  180.  
    scene = new THREE.Scene();
  181.  
    renderer = new THREE.WebGLRenderer({ antialias: true });
  182.  
    renderer.setPixelRatio(window.devicePixelRatio);
  183.  
    renderer.setSize(window.innerWidth, window.innerHeight);
  184.  
    document.body.appendChild(renderer.domElement);
  185.  
     
  186.  
    camera = new THREE.PerspectiveCamera(
  187.  
    60,
  188.  
    window.innerWidth / window.innerHeight,
  189.  
    1,
  190.  
    1000);
  191.  
     
  192.  
    camera.position.set(-0.09397456774197047, -2.5597086635726947, 24.420789670889008);
  193.  
    camera.rotation.set(0.10443543723052419, -0.003827152981119352, 0.0004011488708739715);
  194.  
     
  195.  
    const format = renderer.capabilities.isWebGL2 ?
  196.  
    THREE.RedFormat :
  197.  
    THREE.LuminanceFormat;
  198.  
     
  199.  
    uniforms.tAudioData = {
  200.  
    value: new THREE.DataTexture(analyser.data, fftSize / 2, 1, format)
  201.  
    };
  202.  
     
  203.  
     
  204.  
    addPlane(scene, uniforms, 3000);
  205.  
    addSnow(scene, uniforms);
  206.  
     
  207.  
    range(10).map(i => {
  208.  
    addTree(scene, uniforms, totalPoints, [20, 0, -20 * i]);
  209.  
    addTree(scene, uniforms, totalPoints, [-20, 0, -20 * i]);
  210.  
    });
  211.  
     
  212.  
    const renderScene = new THREE.RenderPass(scene, camera);
  213.  
     
  214.  
    const bloomPass = new THREE.UnrealBloomPass(
  215.  
    new THREE.Vector2(window.innerWidth, window.innerHeight),
  216.  
    1.5,
  217.  
    0.4,
  218.  
    0.85);
  219.  
     
  220.  
    bloomPass.threshold = params.bloomThreshold;
  221.  
    bloomPass.strength = params.bloomStrength;
  222.  
    bloomPass.radius = params.bloomRadius;
  223.  
     
  224.  
    composer = new THREE.EffectComposer(renderer);
  225.  
    composer.addPass(renderScene);
  226.  
    composer.addPass(bloomPass);
  227.  
     
  228.  
    addListners(camera, renderer, composer);
  229.  
    animate();
  230.  
    }
  231.  
     
  232.  
    function animate(time) {
  233.  
    analyser.getFrequencyData();
  234.  
    uniforms.tAudioData.value.needsUpdate = true;
  235.  
    step = (step + 1) % 1000;
  236.  
    uniforms.time.value = time;
  237.  
    uniforms.step.value = step;
  238.  
    composer.render();
  239.  
    requestAnimationFrame(animate);
  240.  
    }
  241.  
     
  242.  
    function loadAudio(i) {
  243.  
    document.getElementById("overlay").innerHTML =
  244.  
    '<div class="text-loading">正在下載音樂,請稍等...</div>';
  245.  
    const files = [
  246.  
    "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/no_curator/Simon_Panrucker/Happy_Christmas_You_Guys/Simon_Panrucker_-_01_-_Snowflakes_Falling_Down.mp3",
  247.  
    "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/no_curator/Dott/This_Christmas/Dott_-_01_-_This_Christmas.mp3",
  248.  
    "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/ccCommunity/TRG_Banks/TRG_Banks_Christmas_Album/TRG_Banks_-_12_-_No_room_at_the_inn.mp3",
  249.  
    "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/ccCommunity/Mark_Smeby/En_attendant_Nol/Mark_Smeby_-_07_-_Jingle_Bell_Swing.mp3"];
  250.  
     
  251.  
    const file = files[i];
  252.  
     
  253.  
    const loader = new THREE.AudioLoader();
  254.  
    loader.load(file, function (buffer) {
  255.  
    audio.setBuffer(buffer);
  256.  
    audio.play();
  257.  
    analyser = new THREE.AudioAnalyser(audio, fftSize);
  258.  
    init();
  259.  
    });
  260.  
     
  261.  
     
  262.  
     
  263.  
     
  264.  
    }
  265.  
     
  266.  
     
  267.  
    function uploadAudio(event) {
  268.  
    document.getElementById("overlay").innerHTML =
  269.  
    '<div class="text-loading">請稍等...</div>';
  270.  
    const files = event.target.files;
  271.  
    const reader = new FileReader();
  272.  
     
  273.  
    reader.onload = function (file) {
  274.  
    var arrayBuffer = file.target.result;
  275.  
     
  276.  
    listener.context.decodeAudioData(arrayBuffer, function (audioBuffer) {
  277.  
    audio.setBuffer(audioBuffer);
  278.  
    audio.play();
  279.  
    analyser = new THREE.AudioAnalyser(audio, fftSize);
  280.  
    init();
  281.  
    });
  282.  
    };
  283.  
     
  284.  
    reader.readAsArrayBuffer(files[0]);
  285.  
    }
  286.  
     
  287.  
    function addTree(scene, uniforms, totalPoints, treePosition) {
  288.  
    const vertexShader = `
  289.  
    attribute float mIndex;
  290.  
    varying vec3 vColor;
  291.  
    varying float opacity;
  292.  
    uniform sampler2D tAudioData;
  293.  
    float norm(float value, float min, float max ){
  294.  
    return (value - min) / (max - min);
  295.  
    }
  296.  
    float lerp(float norm, float min, float max){
  297.  
    return (max - min) * norm + min;
  298.  
    }
  299.  
    float map(float value, float sourceMin, float sourceMax, float destMin, float destMax){
  300.  
    return lerp(norm(value, sourceMin, sourceMax), destMin, destMax);
  301.  
    }
  302.  
    void main() {
  303.  
    vColor = color;
  304.  
    vec3 p = position;
  305.  
    vec4 mvPosition = modelViewMatrix * vec4( p, 1.0 );
  306.  
    float amplitude = texture2D( tAudioData, vec2( mIndex, 0.1 ) ).r;
  307.  
    float amplitudeClamped = clamp(amplitude-0.4,0.0, 0.6 );
  308.  
    float sizeMapped = map(amplitudeClamped, 0.0, 0.6, 1.0, 20.0);
  309.  
    opacity = map(mvPosition.z , -200.0, 15.0, 0.0, 1.0);
  310.  
    gl_PointSize = sizeMapped * ( 100.0 / -mvPosition.z );
  311.  
    gl_Position = projectionMatrix * mvPosition;
  312.  
    }
  313.  
    `;
  314.  
    const fragmentShader = `
  315.  
    varying vec3 vColor;
  316.  
    varying float opacity;
  317.  
    uniform sampler2D pointTexture;
  318.  
    void main() {
  319.  
    gl_FragColor = vec4( vColor, opacity );
  320.  
    gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
  321.  
    }
  322.  
    `;
  323.  
    const shaderMaterial = new THREE.ShaderMaterial({
  324.  
    uniforms: {
  325.  
    ...uniforms,
  326.  
    pointTexture: {
  327.  
    value: new THREE.TextureLoader().load(`https://assets.codepen.io/3685267/spark1.png`)
  328.  
    }
  329.  
    },
  330.  
     
  331.  
     
  332.  
    vertexShader,
  333.  
    fragmentShader,
  334.  
    blending: THREE.AdditiveBlending,
  335.  
    depthTest: false,
  336.  
    transparent: true,
  337.  
    vertexColors: true
  338.  
    });
  339.  
     
  340.  
     
  341.  
    const geometry = new THREE.BufferGeometry();
  342.  
    const positions = [];
  343.  
    const colors = [];
  344.  
    const sizes = [];
  345.  
    const phases = [];
  346.  
    const mIndexs = [];
  347.  
     
  348.  
    const color = new THREE.Color();
  349.  
     
  350.  
    for (let i = 0; i < totalPoints; i++) {
  351.  
    const t = Math.random();
  352.  
    const y = map(t, 0, 1, -8, 10);
  353.  
    const ang = map(t, 0, 1, 0, 6 * TAU) + TAU / 2 * (i % 2);
  354.  
    const [z, x] = polar(ang, map(t, 0, 1, 5, 0));
  355.  
     
  356.  
    const modifier = map(t, 0, 1, 1, 0);
  357.  
    positions.push(x + rand(-0.3 * modifier, 0.3 * modifier));
  358.  
    positions.push(y + rand(-0.3 * modifier, 0.3 * modifier));
  359.  
    positions.push(z + rand(-0.3 * modifier, 0.3 * modifier));
  360.  
     
  361.  
    color.setHSL(map(i, 0, totalPoints, 1.0, 0.0), 1.0, 0.5);
  362.  
     
  363.  
    colors.push(color.r, color.g, color.b);
  364.  
    phases.push(rand(1000));
  365.  
    sizes.push(1);
  366.  
    const mIndex = map(i, 0, totalPoints, 1.0, 0.0);
  367.  
    mIndexs.push(mIndex);
  368.  
    }
  369.  
     
  370.  
    geometry.setAttribute(
  371.  
    "position",
  372.  
    new THREE.Float32BufferAttribute(positions, 3).setUsage(
  373.  
    THREE.DynamicDrawUsage));
  374.  
     
  375.  
     
  376.  
    geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
  377.  
    geometry.setAttribute("size", new THREE.Float32BufferAttribute(sizes, 1));
  378.  
    geometry.setAttribute("phase", new THREE.Float32BufferAttribute(phases, 1));
  379.  
    geometry.setAttribute("mIndex", new THREE.Float32BufferAttribute(mIndexs, 1));
  380.  
     
  381.  
    const tree = new THREE.Points(geometry, shaderMaterial);
  382.  
     
  383.  
    const [px, py, pz] = treePosition;
  384.  
     
  385.  
    tree.position.x = px;
  386.  
    tree.position.y = py;
  387.  
    tree.position.z = pz;
  388.  
     
  389.  
    scene.add(tree);
  390.  
    }
  391.  
     
  392.  
    function addSnow(scene, uniforms) {
  393.  
    const vertexShader = `
  394.  
    attribute float size;
  395.  
    attribute float phase;
  396.  
    attribute float phaseSecondary;
  397.  
    varying vec3 vColor;
  398.  
    varying float opacity;
  399.  
    uniform float time;
  400.  
    uniform float step;
  401.  
    float norm(float value, float min, float max ){
  402.  
    return (value - min) / (max - min);
  403.  
    }
  404.  
    float lerp(float norm, float min, float max){
  405.  
    return (max - min) * norm + min;
  406.  
    }
  407.  
    float map(float value, float sourceMin, float sourceMax, float destMin, float destMax){
  408.  
    return lerp(norm(value, sourceMin, sourceMax), destMin, destMax);
  409.  
    }
  410.  
    void main() {
  411.  
    float t = time* 0.0006;
  412.  
    vColor = color;
  413.  
    vec3 p = position;
  414.  
    p.y = map(mod(phase+step, 1000.0), 0.0, 1000.0, 25.0, -8.0);
  415.  
    p.x += sin(t+phase);
  416.  
    p.z += sin(t+phaseSecondary);
  417.  
    opacity = map(p.z, -150.0, 15.0, 0.0, 1.0);
  418.  
    vec4 mvPosition = modelViewMatrix * vec4( p, 1.0 );
  419.  
    gl_PointSize = size * ( 100.0 / -mvPosition.z );
  420.  
    gl_Position = projectionMatrix * mvPosition;
  421.  
    }
  422.  
    `;
  423.  
     
  424.  
    const fragmentShader = `
  425.  
    uniform sampler2D pointTexture;
  426.  
    varying vec3 vColor;
  427.  
    varying float opacity;
  428.  
    void main() {
  429.  
    gl_FragColor = vec4( vColor, opacity );
  430.  
    gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
  431.  
    }
  432.  
    `;
  433.  
    function createSnowSet(sprite) {
  434.  
    const totalPoints = 300;
  435.  
    const shaderMaterial = new THREE.ShaderMaterial({
  436.  
    uniforms: {
  437.  
    ...uniforms,
  438.  
    pointTexture: {
  439.  
    value: new THREE.TextureLoader().load(sprite)
  440.  
    }
  441.  
    },
  442.  
     
  443.  
     
  444.  
    vertexShader,
  445.  
    fragmentShader,
  446.  
    blending: THREE.AdditiveBlending,
  447.  
    depthTest: false,
  448.  
    transparent: true,
  449.  
    vertexColors: true
  450.  
    });
  451.  
     
  452.  
     
  453.  
    const geometry = new THREE.BufferGeometry();
  454.  
    const positions = [];
  455.  
    const colors = [];
  456.  
    const sizes = [];
  457.  
    const phases = [];
  458.  
    const phaseSecondaries = [];
  459.  
     
  460.  
    const color = new THREE.Color();
  461.  
     
  462.  
    for (let i = 0; i < totalPoints; i++) {
  463.  
    const [x, y, z] = [rand(25, -25), 0, rand(15, -150)];
  464.  
    positions.push(x);
  465.  
    positions.push(y);
  466.  
    positions.push(z);
  467.  
     
  468.  
    color.set(randChoise(["#f1d4d4", "#f1f6f9", "#eeeeee", "#f1f1e8"]));
  469.  
     
  470.  
    colors.push(color.r, color.g, color.b);
  471.  
    phases.push(rand(1000));
  472.  
    phaseSecondaries.push(rand(1000));
  473.  
    sizes.push(rand(4, 2));
  474.  
    }
  475.  
     
  476.  
    geometry.setAttribute(
  477.  
    "position",
  478.  
    new THREE.Float32BufferAttribute(positions, 3));
  479.  
     
  480.  
    geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
  481.  
    geometry.setAttribute("size", new THREE.Float32BufferAttribute(sizes, 1));
  482.  
    geometry.setAttribute("phase", new THREE.Float32BufferAttribute(phases, 1));
  483.  
    geometry.setAttribute(
  484.  
    "phaseSecondary",
  485.  
    new THREE.Float32BufferAttribute(phaseSecondaries, 1));
  486.  
     
  487.  
     
  488.  
    const mesh = new THREE.Points(geometry, shaderMaterial);
  489.  
     
  490.  
    scene.add(mesh);
  491.  
    }
  492.  
    const sprites = [
  493.  
    "https://assets.codepen.io/3685267/snowflake1.png",
  494.  
    "https://assets.codepen.io/3685267/snowflake2.png",
  495.  
    "https://assets.codepen.io/3685267/snowflake3.png",
  496.  
    "https://assets.codepen.io/3685267/snowflake4.png",
  497.  
    "https://assets.codepen.io/3685267/snowflake5.png"];
  498.  
     
  499.  
    sprites.forEach(sprite => {
  500.  
    createSnowSet(sprite);
  501.  
    });
  502.  
    }
  503.  
     
  504.  
    function addPlane(scene, uniforms, totalPoints) {
  505.  
    const vertexShader = `
  506.  
    attribute float size;
  507.  
    attribute vec3 customColor;
  508.  
    varying vec3 vColor;
  509.  
    void main() {
  510.  
    vColor = customColor;
  511.  
    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
  512.  
    gl_PointSize = size * ( 300.0 / -mvPosition.z );
  513.  
    gl_Position = projectionMatrix * mvPosition;
  514.  
    }
  515.  
    `;
  516.  
    const fragmentShader = `
  517.  
    uniform vec3 color;
  518.  
    uniform sampler2D pointTexture;
  519.  
    varying vec3 vColor;
  520.  
    void main() {
  521.  
    gl_FragColor = vec4( vColor, 1.0 );
  522.  
    gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
  523.  
    }
  524.  
    `;
  525.  
    const shaderMaterial = new THREE.ShaderMaterial({
  526.  
    uniforms: {
  527.  
    ...uniforms,
  528.  
    pointTexture: {
  529.  
    value: new THREE.TextureLoader().load(`https://assets.codepen.io/3685267/spark1.png`)
  530.  
    }
  531.  
    },
  532.  
     
  533.  
     
  534.  
    vertexShader,
  535.  
    fragmentShader,
  536.  
    blending: THREE.AdditiveBlending,
  537.  
    depthTest: false,
  538.  
    transparent: true,
  539.  
    vertexColors: true
  540.  
    });
  541.  
     
  542.  
     
  543.  
    const geometry = new THREE.BufferGeometry();
  544.  
    const positions = [];
  545.  
    const colors = [];
  546.  
    const sizes = [];
  547.  
     
  548.  
    const color = new THREE.Color();
  549.  
     
  550.  
    for (let i = 0; i < totalPoints; i++) {
  551.  
    const [x, y, z] = [rand(-25, 25), 0, rand(-150, 15)];
  552.  
    positions.push(x);
  553.  
    positions.push(y);
  554.  
    positions.push(z);
  555.  
     
  556.  
    color.set(randChoise(["#93abd3", "#f2f4c0", "#9ddfd3"]));
  557.  
     
  558.  
    colors.push(color.r, color.g, color.b);
  559.  
    sizes.push(1);
  560.  
    }
  561.  
     
  562.  
    geometry.setAttribute(
  563.  
    "position",
  564.  
    new THREE.Float32BufferAttribute(positions, 3).setUsage(
  565.  
    THREE.DynamicDrawUsage));
  566.  
     
  567.  
     
  568.  
    geometry.setAttribute(
  569.  
    "customColor",
  570.  
    new THREE.Float32BufferAttribute(colors, 3));
  571.  
     
  572.  
    geometry.setAttribute("size", new THREE.Float32BufferAttribute(sizes, 1));
  573.  
     
  574.  
    const plane = new THREE.Points(geometry, shaderMaterial);
  575.  
     
  576.  
    plane.position.y = -8;
  577.  
    scene.add(plane);
  578.  
    }
  579.  
     
  580.  
    function addListners(camera, renderer, composer) {
  581.  
    document.addEventListener("keydown", e => {
  582.  
    const { x, y, z } = camera.position;
  583.  
    console.log(`camera.position.set(${x},${y},${z})`);
  584.  
    const { x: a, y: b, z: c } = camera.rotation;
  585.  
    console.log(`camera.rotation.set(${a},$,${c})`);
  586.  
    });
  587.  
     
  588.  
    window.addEventListener(
  589.  
    "resize",
  590.  
    () => {
  591.  
    const width = window.innerWidth;
  592.  
    const height = window.innerHeight;
  593.  
     
  594.  
    camera.aspect = width / height;
  595.  
    camera.updateProjectionMatrix();
  596.  
     
  597.  
    renderer.setSize(width, height);
  598.  
    composer.setSize(width, height);
  599.  
    },
  600.  
    false);
  601.  
     
  602.  
    }
  603.  
    </script>
  604.  
     
  605.  
    </body>
  606.  
     
  607.  
    </html>
 

WebSocket:實(shí)現(xiàn)實(shí)時雙向數(shù)據(jù)傳輸?shù)腤eb通信協(xié)議

前端達(dá)人

 

前言

在當(dāng)今互聯(lián)網(wǎng)時代,實(shí)時通信已成為很多應(yīng)用的需求。為了滿足這種需求,WebSocket協(xié)議被設(shè)計(jì)出來。WebSocket是一種基于TCP議的全雙工通信協(xié)議,通過WebSocket,Web應(yīng)用程序可以與服務(wù)器建立持久的連接,實(shí)現(xiàn)實(shí)時雙向數(shù)據(jù)輸,提供極低的延遲和高效的數(shù)據(jù)傳輸。


WebSocket原理

  • HTTP請求-響應(yīng)協(xié)議

在理解WebSocket原理之前,我們需要了解HTTP請求-響應(yīng)協(xié)議。HTTP是一種無狀態(tài)的請求-響應(yīng)協(xié)議,客戶端通過發(fā)送HTTP請求到服務(wù)器,服務(wù)器接收并處理請求,并返回HTTP響應(yīng)給客戶端。但是,在傳統(tǒng)的HTTP協(xié)議中,客戶端只能發(fā)送請求,而服務(wù)器只能通過響應(yīng)來處理客戶端的請求。

  • WebSocket協(xié)議

WebSocket協(xié)議是在HTTP協(xié)議的基礎(chǔ)上進(jìn)行擴(kuò)展的。在建立WebSocket連接時,客戶端首先發(fā)送一個HTTP請求到服務(wù)器,并將Upgrade頭部字段設(shè)置為"websocket",表示希望升級到WebSocket協(xié)議。服務(wù)器接收到這個請求后,如果支持WebSocket協(xié)議,會返回一個狀態(tài)碼101 Switching Protocols的HTTP響應(yīng),并通過Upgrade頭部字段將連接升級為WebSocket連接。

升級完成后,客戶端和服務(wù)器之間的通信不再遵循HTTP請求-響應(yīng)模式,而是通過WebSocket協(xié)議進(jìn)行雙向的實(shí)時通信。客戶端和服務(wù)器可以直接發(fā)送消息給對方,不需要等待對方的請求。


如何使用WebSocket

建立WebSocket連接:

要建立WebSocket連接,需要在客戶端和服務(wù)器之間進(jìn)行系列的握手操作。下面是詳細(xì)的代碼教程,示了如何在Web應(yīng)用程序中建立WebSocket連接。

在戶端(JavaScript):

// 創(chuàng)建WebSocket對象并指定服務(wù)器地址
var socket = new WebSocket("ws://example.com/socket");

// 監(jiān)聽連接建立事件
socket.onopen = function() {
console.log("WebSocket連接已建立");
// 在連接建立后,可以發(fā)送消息到服務(wù)器
socket.send("Hello Server!");
};


// 監(jiān)聽接收到服務(wù)器發(fā)送的消息
socket.onmessage = function(event) {
var message = event.data;
console.log("接收到服務(wù)器發(fā)送的消息:" + message);
};


// 監(jiān)聽連接關(guān)閉事件
socket.onclose = function(event) {
console.log("WebSocket連接已關(guān)閉");
};


// 監(jiān)聽連接錯誤事件
socket.onerror = function(event) {
console.error("WebSocket連接錯誤:" + event};

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

在服務(wù)器端(示例使用Node.js):

const WebSocket = require("ws");

// 創(chuàng)建WebSocket服務(wù)器
const wss = new WebSocket.Server({ port: 8080 });


// 監(jiān)聽連接建立事件
wss.on("connection", function(socket) {
console.log("WebSocket連接已建立");


// 監(jiān)聽接收到客戶端發(fā)送的消息
socket.on("message", function(message) {
console.log("接收到戶端發(fā)送的消息:" + message);


<span class="token comment">// 向客戶端發(fā)送消息</span>
socket<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">"Hello Client!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

});


// 監(jiān)聽連接關(guān)閉事件
socket.on("close", function() {
console.log("WebSocket連接已關(guān)閉");
});
});

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在以上代碼中,客戶端通過創(chuàng)建WebSocket對象,并指定服務(wù)器地址"ws://example.com/socket"來建立WebSocket連接。同時,客戶端通過監(jiān)聽onopen事件,可以在連接建立后發(fā)送消息到服務(wù)器。服務(wù)器端使用WebSocket.Server類創(chuàng)建WebSocket服務(wù)器,并監(jiān)聽"connection事件來處理連接建立后的操作。服務(wù)器端通過socket.on(“message”)來監(jiān)聽接收到客戶端發(fā)送的消息,并通過socket.send()向客戶端發(fā)送消息。

數(shù)據(jù)傳輸:

建立WebSocket連接后,客戶端和服務(wù)器可以通過WebSocket對象進(jìn)行雙向的實(shí)時數(shù)據(jù)傳輸。下面是一個示例代碼,演示了如何在客戶端和服務(wù)器之間進(jìn)行數(shù)據(jù)傳輸。

在客戶端(JavaScript):

// 發(fā)送消息到服務(wù)器
socket.send("Hello Server!");

// 監(jiān)聽接收到服務(wù)器發(fā)送的消息
socket.onmessage = function(event) {
var message = event.data;
console.log("接收到服務(wù)器發(fā)送的消息:" + message);
};

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在服務(wù)器端(示例使用Node.js):

// 向客戶端發(fā)送消息
socket.send("Hello Client!");

// 監(jiān)聽接收到客戶端發(fā)送的消息
socket.on("message", function(message) {
console.log("接收到客戶端發(fā)送的消息:" + message);
});

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在以上代碼中,客戶端通過調(diào)用socket.send()方法將消息發(fā)送到服務(wù)器,服務(wù)器通過socket.send()方法將消息發(fā)送到客戶端??蛻舳送ㄟ^監(jiān)聽socket.onmessage事件來接收服務(wù)器發(fā)送的消息,服務(wù)器通過監(jiān)聽socket.on("message")事件來接收客戶端發(fā)送的消息。

通過以上代碼示例,你可以詳細(xì)了解如何使用WebSocket建立連接并進(jìn)行數(shù)據(jù)傳輸。請注意,示例代碼中使用的服務(wù)器地址和端口號需要根據(jù)實(shí)際情況進(jìn)行修改。同時,你還可以在具體應(yīng)用中根據(jù)需要使用WebSocket的其他方法和事件來實(shí)現(xiàn)更復(fù)雜的功能。


WebSocket的真實(shí)使用場景

即時通訊:

WebSocket非常適合用于即時通訊應(yīng)用,因?yàn)樗軌驅(qū)崿F(xiàn)實(shí)時雙向通信。以下是一個簡單的即時聊天應(yīng)用的代碼教程。

在客戶端(JavaScript):

// 創(chuàng)建WebSocket對象并指定服務(wù)器地址
var socket = new WebSocket("ws://example.com/socket");

// 監(jiān)聽連接建立事件
socket.onopen = function() {
console.log("WebSocket連接已建立");


// 監(jiān)聽文本框輸入,按下Enter鍵時發(fā)送消息
var input = document.getElementById("input");
input.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
var message = input.value;
socket.send(message);
input.value = "";
}
});
};


// 監(jiān)聽接收到服務(wù)器發(fā)送的消息
socket.onmessage = function(event) {
var message = event.data;
console.log("接收到服務(wù)器發(fā)送的消息:" + message);


// 將接收到的消息顯示在聊天窗口中
var chatWindow = document.getElementById("chatWindow");
chatWindow.innerHTML += "<p>" + message + "</p>";
};


// 監(jiān)聽連接關(guān)閉事件
socket.onclose = function(event) {
console.log("WebSocket連接已關(guān)閉");
};


// 監(jiān)聽連接錯誤事件
socket.onerror = function(event) {
console.error("WebSocket連接錯誤:" + event};

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

在服務(wù)器端(示例使用Node.js):

const WebSocket = require("ws");

// 創(chuàng)建WebSocket服務(wù)器
const wss = new WebSocket.Server({ port: 8080 });


// 監(jiān)聽連接建立事件
wss.on("connection", function(socket) {
console.log("WebSocket連接已建立");


// 監(jiān)聽接收到客戶端發(fā)送的消息
socket.on("message", function(message) {
console.log("接收到客戶端發(fā)送的消息:" + message);


<span class="token comment">// 向所有連接的客戶端發(fā)送消息</span>
wss<span class="token punctuation">.</span>clients<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">client</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  client<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

});


// 監(jiān)聽連接關(guān)閉事件
socket.on("close", function() {
console.log("WebSocket連接已關(guān)閉");
});
});

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

在上述代碼中,客戶端通過創(chuàng)建WebSocket對象連接到服務(wù)器。輸入框中的文本框用于錄入要發(fā)送的消息,按下Enter鍵時會將消息發(fā)送給服務(wù)器。服務(wù)器接收到消息后,通過遍歷所有連接的客戶端,向每個客戶端發(fā)送消息。

這樣,多個客戶端就可以實(shí)時地進(jìn)行聊天,并且所有的消息都會實(shí)時地在各個客戶端之間同步顯示。

多人協(xié)作:

WebSocket還可用于多人協(xié)作應(yīng)用,讓多個用戶可以實(shí)時地協(xié)同編輯文檔或畫布。以下是一個簡單的代碼教程。

在客戶端(JavaScript):

// 創(chuàng)建WebSocket對象并指定服務(wù)器地址
var socket = new WebSocket("ws://example.com/socket");

// 監(jiān)聽連接建立事件
socket.onopen = function() {
console.log("WebSocket連接已建立");


// 監(jiān)聽文本框輸入,按下Enter鍵時發(fā)送繪畫指令
var canvas = document.getElementById("canvas");
canvas.addEventListener("mousedown", function(event) {
// 繪畫指令的數(shù)據(jù)格式可以自定義,這里使用了簡單的示例
var instruction = {
type: "draw",
position: {
x: event.clientX,
y: event.clientY
}
};
socket.send(JSON.stringify(instruction));
});
};


// 監(jiān)聽接收到服務(wù)器發(fā)送的消息
socket.onmessage = function(event) {
var message = JSON.parse(event.data);
console.log("接收到服務(wù)器發(fā)送的消息:" + message);


// 根據(jù)消息執(zhí)行相應(yīng)的操作,示例中處理了繪畫指令
if (message.type === "draw") {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(message.position.x, message.position.y, 5, 0, 2 * Math.PI);
ctx.fill();
}
};


// 監(jiān)聽連接關(guān)閉事件
socket.onclose = function(event) {
console.log("WebSocket連接已關(guān)閉");
};


// 監(jiān)聽連接錯誤事件
socket.onerror = function(event) {
console.error("WebSocket連接錯誤:" + event};

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

在服務(wù)器端(示例使用Node.js):

const WebSocket = require("ws");

// 創(chuàng)建WebSocket服務(wù)器
const wss = new WebSocket.Server({ port: 8080 });


// 監(jiān)聽連接建立事件
wss.on("connection", function(socket) {
console.log("WebSocket連接已建立");


// 監(jiān)聽接收到客戶端發(fā)送的消息
socket.on("message", function(message) {
console.log("接收到客戶端發(fā)送的消息:" + message);


<span class="token comment">// 向所有連接的客戶端發(fā)送消息</span>
wss<span class="token punctuation">.</span>clients<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">client</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  client<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

});


// 監(jiān)聽連接關(guān)閉事件
socket.on("close", function() {
console.log("WebSocket連接已關(guān)閉");
});
});

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

在上述代碼中,客戶端通過創(chuàng)建WebSocket對象連接到服務(wù)器。當(dāng)鼠標(biāo)在畫布上按下時,將繪畫指令發(fā)送給服務(wù)器。服務(wù)器接收到繪畫指令后,將指令廣播給所有連接的客戶端,并在各個客戶端上進(jìn)行繪畫操作。

這樣,多個用戶就可以實(shí)時地協(xié)同編輯同一個畫布或文檔,所有的繪畫指令都會即時同步在各個客戶端之間。

實(shí)時數(shù)據(jù)更新:

WebSocket還可以用于實(shí)時數(shù)據(jù)更新應(yīng)用,例如股票交易應(yīng)用中的實(shí)時股票價格更新。以下是一個簡單的代碼教程。

在客戶端(JavaScript):

// 創(chuàng)建WebSocket對象并指定服務(wù)器地址
var socket = new WebSocket("鏈接");

// 監(jiān)聽連接建立事件
socket.onopen = function() {
console.log("WebSocket連接已建立");
};


// 監(jiān)聽接收到服務(wù)器發(fā)送的消息
socket.onmessage = function(event) {
var message = JSON.parse(event.data);
console.log("接收到服務(wù)器發(fā)送的消息:" + message);


// 對接收到的實(shí)時數(shù)據(jù)進(jìn)行處理
var stockPriceElement = document.getElementById("stockPrice");
stockPriceElement.innerText = message.price;
};


// 監(jiān)聽連接關(guān)閉事件
socket.onclose = function(event) {
console.log("WebSocket連接已關(guān)閉");
};


// 監(jiān)聽連接錯誤事件
socket.onerror = function(event) {
console.error("WebSocket連接錯誤:" + event};

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在服務(wù)器端(示例使用Node.js):

const WebSocket = require("ws");

// 創(chuàng)建WebSocket服務(wù)器
const wss = new WebSocket.Server({ port: 8080 });


// 模擬實(shí)時股票價格更新
setInterval(function() {
var stockPrice = Math.random() * 100;


// 向所有連接的客戶端發(fā)送實(shí)時數(shù)據(jù)
wss.clients.forEach(function(client) {
var data = {
price: stockPrice
};
client.send(JSON.stringify(data));
});
}, 2000);


// 監(jiān)聽連接建立事件
wss.on("connection", function(socket) {
console.log("WebSocket連接已建立");


// 初始化發(fā)送實(shí)時數(shù)據(jù)
var stockPrice = Math.random() * 100;
var data = {
price: stockPrice
};
socket.send(JSON.stringify(data));


// 監(jiān)聽連接關(guān)閉事件
socket.on("close", function() {
console.log("WebSocket連接已關(guān)閉");
});
});

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

在上述代碼中,客戶端通過創(chuàng)建WebSocket對象連接服務(wù)器。服務(wù)器使用setInterval函數(shù)模擬實(shí)時股票價格的更新,并將更新的數(shù)據(jù)發(fā)送給所有連接的客戶端??蛻舳吮O(jiān)聽接收到服務(wù)器發(fā)送的消息,并處理接收到的實(shí)時數(shù)據(jù)。

這樣,在股票交易應(yīng)用中,多個用戶可以實(shí)時地接收和顯示股票價格的更新信息。包括打游戲的時候,隊(duì)友之間互相溝通,打字交流,或者走位,放技能等等,都是即時的。


WebSocket的優(yōu)勢與局限性

  • WebSocket的優(yōu)勢:
  • 雙向?qū)崟r通信:WebSocket提供了雙向的實(shí)時信能力,客戶端和服務(wù)器可以通過該協(xié)議進(jìn)行雙向數(shù)據(jù)傳輸,實(shí)時反饋更新信息,實(shí)現(xiàn)即時通訊、實(shí)時數(shù)據(jù)推送等功能。

  • 較低的延遲:與傳統(tǒng)的HTTP請求相比,WebSocket降低了通信的開銷,減少了傳輸和處理數(shù)據(jù)的延遲,因此可以更快進(jìn)行實(shí)時數(shù)據(jù)傳輸。

  • 更高的性能:由于WebSocket使用較少的頭部信息和更有效的消息傳輸格式,因此在相同帶寬下可以傳輸更多的數(shù)據(jù),提高了性能和效率。

  • 廣泛的瀏覽器支持:WebSocket是HTML5的一部分,并且得到了大多數(shù)現(xiàn)代瀏覽器的支持,因此它可以在各種平臺和設(shè)備上使用。

  • 連接保持:與傳統(tǒng)的HTTP請求不同,WebSocket連接保持在建立之后,雙方可以隨時進(jìn)行數(shù)據(jù)傳輸,避免了不必要的連接和斷開操作。

  • WebSocket的局限性:
  • 兼容性問題:雖然現(xiàn)代瀏覽器廣泛支持WebSocket,但在某些舊版本或特定設(shè)備上可能存在兼容性問題。為了兼容性,可以使用輪訓(xùn)技術(shù)(如長輪詢)作為備選方案。

  • 部署和維護(hù)復(fù)雜性:WebSocket服務(wù)器的設(shè)置和配置可能比傳統(tǒng)的Web服務(wù)器復(fù)雜一些,需要專門的服務(wù)器環(huán)境和配置。

  • 安全性問題:由于WebSocket是在HTTP協(xié)議的基礎(chǔ)上建立的,它們共享相同的安全風(fēng)險(xiǎn),例如跨站點(diǎn)腳本(XSS)和跨站請求偽造(CSRF)。因此,在使用WebSocket時需要考慮到安全性,并采取適當(dāng)?shù)陌踩胧?/p>

  • 擴(kuò)展問題:WebSocket協(xié)議還不支持像HTTP/2那樣的一些高級特性,例如頭部壓縮和流量控制。在某些特殊情況下,可能需要通過其他方式實(shí)現(xiàn)這些功能。

盡管WebSocket具有上述局限性,但它仍然是實(shí)時通訊、實(shí)時數(shù)據(jù)傳輸和實(shí)時協(xié)作等場景下的首選協(xié)議,因?yàn)樗邆淞穗p向?qū)崟r通信和較低延遲等一系列的優(yōu)勢。在開發(fā)時,需要根據(jù)具體需求和限制,綜合考慮使用WebSocket的適用性。


結(jié)論

WebSocket是一種能夠提供雙向?qū)崟r通信的協(xié)議,適用于需要實(shí)時數(shù)據(jù)傳輸和雙向通信的場景。它具有較低的延遲、更高的性和廣泛的瀏覽器持等優(yōu)勢,能夠?qū)崿F(xiàn)即時通訊、多人協(xié)和實(shí)時數(shù)據(jù)更新等功能。

然而,WebSocket也存在兼容性、部署和維護(hù)復(fù)雜性、安全性問題以及缺乏一些高級特性等局限性。在開發(fā)時,需要仔細(xì)考慮具體需求和限制,并必要時采取適當(dāng)?shù)慕鉀Q方案。

總的來說,WebSocket在實(shí)時通信和實(shí)時數(shù)據(jù)傳輸方面具有明顯的優(yōu)勢,是構(gòu)建現(xiàn)代Web應(yīng)用的重要工具之一。

藍(lán)藍(lán)設(shè)計(jì)(sillybuy.com )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的大數(shù)據(jù)可視化界面設(shè)計(jì)、B端界面設(shè)計(jì)、桌面端界面設(shè)計(jì)、APP界面設(shè)計(jì)、圖標(biāo)定制、用戶體驗(yàn)設(shè)計(jì)、交互設(shè)計(jì)UI咨詢、高端網(wǎng)站設(shè)計(jì)、平面設(shè)計(jì),以及相關(guān)的軟件開發(fā)服務(wù),咨詢電話:01063334945。

關(guān)鍵詞:UI咨詢、UI設(shè)計(jì)服務(wù)公司軟件界面設(shè)計(jì)公司、界面設(shè)計(jì)公司、UI設(shè)計(jì)公司、UI交互設(shè)計(jì)公司、數(shù)據(jù)可視化設(shè)計(jì)公司、用戶體驗(yàn)公司高端網(wǎng)站設(shè)計(jì)公司

銀行金融軟件UI界面設(shè)計(jì)、能源及監(jiān)控軟件UI界面設(shè)計(jì)氣象行業(yè)UI界面設(shè)計(jì)、軌道交通界面設(shè)計(jì)地理信息系統(tǒng)GIS UI界面設(shè)計(jì)、航天軍工軟件UI界面設(shè)計(jì)醫(yī)療行業(yè)軟件UI界面設(shè)計(jì)、教育行業(yè)軟件UI界面設(shè)計(jì)、企業(yè)信息化UI界面設(shè)計(jì)、軟件qt開發(fā)、軟件wpf開發(fā)、軟件vue開發(fā)

Vue2 watch監(jiān)聽props的值

前端達(dá)人

再次遇到監(jiān)聽子組件收到父組件傳過來的值,如果這個值變化,頁面中的值發(fā)現(xiàn)是不會跟著同步變化的。所以監(jiān)聽props中的值,一直監(jiān)聽。

 

代碼:

 
  1.  
    props: {
  2.  
    start:{
  3.  
    type: String,
  4.  
    },
  5.  
    end:{
  6.  
    type: String,
  7.  
    }
  8.  
    },
 

 

 
  1.  
    computed:{
  2.  
    myStart:function(){
  3.  
    return this.start
  4.  
    },
  5.  
    myEnd:function(){
  6.  
    return this.end
  7.  
    }
  8.  
    },
  9.  
    watch: {
  10.  
    myStart:function(newVal){
  11.  
    if(newVal){
  12.  
    this.startTime=newVal
  13.  
    }
  14.  
    },
  15.  
    myEnd:function(newVal){
  16.  
    if(newVal){
  17.  
    this.endTime=newVal
  18.  
    }
  19.  
    },
  20.  

藍(lán)藍(lán)設(shè)計(jì)(sillybuy.com )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的大數(shù)據(jù)可視化界面設(shè)計(jì)、B端界面設(shè)計(jì)、桌面端界面設(shè)計(jì)、APP界面設(shè)計(jì)、圖標(biāo)定制、用戶體驗(yàn)設(shè)計(jì)、交互設(shè)計(jì)UI咨詢、高端網(wǎng)站設(shè)計(jì)平面設(shè)計(jì),以及相關(guān)的軟件開發(fā)服務(wù),咨詢電話:01063334945。

關(guān)鍵詞:UI咨詢、UI設(shè)計(jì)服務(wù)公司軟件界面設(shè)計(jì)公司、界面設(shè)計(jì)公司、UI設(shè)計(jì)公司、UI交互設(shè)計(jì)公司、數(shù)據(jù)可視化設(shè)計(jì)公司、用戶體驗(yàn)公司高端網(wǎng)站設(shè)計(jì)公司

銀行金融軟件UI界面設(shè)計(jì)、能源及監(jiān)控軟件UI界面設(shè)計(jì)氣象行業(yè)UI界面設(shè)計(jì)、軌道交通界面設(shè)計(jì)地理信息系統(tǒng)GIS UI界面設(shè)計(jì)、航天軍工軟件UI界面設(shè)計(jì)、醫(yī)療行業(yè)軟件UI界面設(shè)計(jì)教育行業(yè)軟件UI界面設(shè)計(jì)、企業(yè)信息化UI界面設(shè)計(jì)、軟件qt開發(fā)、軟件wpf開發(fā)軟件vue開發(fā)

什么是前端安全性(front-end security)?列舉一些前端安全性的最佳實(shí)踐

前端達(dá)人

前端入門之旅:探索Web開發(fā)的奇妙世界 歡迎來到前端入門之旅!感興趣的可以訂閱本專欄哦!這個專欄是為那些對Web開發(fā)感興趣、剛剛踏入前端領(lǐng)域的朋友們量身打造的。無論你是完全的新手還是有一些基礎(chǔ)的開發(fā)者,這里都將為你提供一個系統(tǒng)而又親切的學(xué)習(xí)平臺。在這個專欄中,我們將以問答形式每天更新,為大家呈現(xiàn)精選的前端知識點(diǎn)和常見問題解答。通過問答形式,我們希望能夠更直接地回應(yīng)讀者們對于前端技術(shù)方面的疑問,并且?guī)椭蠹抑鸩浇⑵鹨粋€扎實(shí)的基礎(chǔ)。無論是HTML、CSS、JavaScript還是各種常用框架和工具,我們將深入淺出地解釋概念,并提供實(shí)際案例和練習(xí)來鞏固所學(xué)內(nèi)容。同時,我們也會分享一些實(shí)用技巧和最佳實(shí)踐,幫助你更好地理解并運(yùn)用前端開發(fā)中的各種技術(shù)。

無論你是尋找職業(yè)轉(zhuǎn)型、提升技能還是滿足個人興趣,我們都將全力以赴,為你提供最優(yōu)質(zhì)的學(xué)習(xí)資源和支持。讓我們一起探索Web開發(fā)的奇妙世界吧!加入前端入門之旅,成為一名出色的前端開發(fā)者! 讓我們啟航前端之旅?。?!


前端安全性概述及最佳實(shí)踐

前端安全性是指在前端開發(fā)中采取的一系列措施,旨在保護(hù)應(yīng)用程序、用戶數(shù)據(jù)以及用戶隱私免受各種安全威脅。以下是一些前端安全性的最佳實(shí)踐:

  1. HTTPS 使用:

    • 使用HTTPS協(xié)議確保數(shù)據(jù)在傳輸過程中的加密,防止中間人攻擊。
  2. 內(nèi)容安全策略(CSP):

    • 使用CSP來限制瀏覽器加載頁面中的資源,防止惡意腳本注入。
  3. 跨站腳本攻擊(XSS)防護(hù):

    • 對用戶輸入和動態(tài)生成的內(nèi)容進(jìn)行合適的轉(zhuǎn)義或編碼。
    • 使用HTTP Only 標(biāo)記來防止腳本操作 cookie。
  4. 跨站請求偽造(CSRF)防護(hù):

    • 使用合適的令牌(CSRF Token)來驗(yàn)證請求的合法性。
  5. 安全的跨域資源共享(CORS)配置:

    • 限制允許訪問資源的域,防止不受信任的域發(fā)起請求。
  6. 安全的第三方庫和框架:

    • 使用官方版本的庫和框架,避免使用已知的有安全漏洞的版本。
  7. 安全的存儲和傳輸:

    • 避免在前端存儲敏感信息,如密碼,而應(yīng)交由后端進(jìn)行處理。
    • 在數(shù)據(jù)傳輸時使用加密算法,確保數(shù)據(jù)在傳輸過程中的保密性。
  8. 用戶身份驗(yàn)證和授權(quán):

    • 使用安全的身份驗(yàn)證方法,如OAuth或OpenID Connect。
    • 僅在有必要的情況下授予用戶特定的權(quán)限。
  9. 不使用過期或不安全的特性:

    • 避免使用已經(jīng)過時或不再維護(hù)的前端框架和庫。
    • 避免使用不安全的瀏覽器特性,如棄用的插件。
  10. 前端路由安全:

    • 使用前端路由時,確保路由的訪問權(quán)限得到合理管理,防止越權(quán)訪問。
  11. 監(jiān)測和報(bào)告安全事件:

    • 集成日志記錄和監(jiān)控機(jī)制,及時發(fā)現(xiàn)異常行為。
    • 實(shí)現(xiàn)安全事件報(bào)告,以便及時采取措施應(yīng)對攻擊。
  12. 教育和培訓(xùn):

    • 對開發(fā)團(tuán)隊(duì)進(jìn)行安全性培訓(xùn),提高對潛在威脅的認(rèn)識。
    • 定期進(jìn)行代碼審查,確保代碼符合最佳安全實(shí)踐。
  13. 安全頭部的使用:

    • 使用HTTP頭部來加強(qiáng)安全性,如Strict-Transport-Security(HSTS)。
  14. 定期進(jìn)行安全性測試:

    • 進(jìn)行定期的安全性測試,包括靜態(tài)代碼分析和滲透測試,以確保發(fā)現(xiàn)和修復(fù)潛在的安全漏洞。

這些最佳實(shí)踐有助于構(gòu)建更加安全、可靠的前端應(yīng)用程序,減少潛在的攻擊風(fēng)險(xiǎn)。前端安全性是一個不斷演變的領(lǐng)域,開發(fā)者應(yīng)該時刻關(guān)注新的安全威脅和最佳實(shí)踐。


 

本專欄適用讀者比較廣泛,適用于前端初學(xué)者;或者沒有學(xué)過前端對前端有興趣的伙伴,亦或者是后端同學(xué)想在面試過程中能夠更好的展示自己拓展一些前端小知識點(diǎn),所以如果你具備了前端的基礎(chǔ)跟著本專欄學(xué)習(xí),也是可以很大程度幫助你查漏補(bǔ)缺,由于博主本人是自己再做內(nèi)容輸出,如果文中出現(xiàn)有瑕疵的地方各位可以通過主頁的左側(cè)聯(lián)系我,我們一起進(jìn)步,與此同時也推薦大家?guī)追輰冢信d趣的伙伴可以訂閱一下:除了下方的專欄外大家也可以到我的主頁能看到其他的專欄;

前端小游戲(免費(fèi))這份專欄將帶你進(jìn)入一個充滿創(chuàng)意和樂趣的世界,通過利用HTML、CSS和JavaScript的基礎(chǔ)知識,我們將一起搭建各種有趣的頁面小游戲。無論你是初學(xué)者還是有一些前端開發(fā)經(jīng)驗(yàn),這個專欄都適合你。我們會從最基礎(chǔ)的知識開始,循序漸進(jìn)地引導(dǎo)你掌握構(gòu)建頁面游戲所需的技能。通過實(shí)際案例和練習(xí),你將學(xué)會如何運(yùn)用HTML來構(gòu)建頁面結(jié)構(gòu),使用CSS來美化游戲界面,并利用JavaScript為游戲添加交互和動態(tài)效果。在這個專欄中,我們將涵蓋各種類型的小游戲,包括迷宮游戲、打磚塊、貪吃蛇、掃雷、計(jì)算器、飛機(jī)大戰(zhàn)、井字游戲、拼圖、迷宮等等。每個項(xiàng)目都會以簡潔明了的步驟指導(dǎo)你完成搭建過程,并提供詳細(xì)解釋和代碼示例。同時,我們也會分享一些優(yōu)化技巧和最佳實(shí)踐,幫助你提升頁面性能和用戶體驗(yàn)。無論你是想尋找一個有趣的項(xiàng)目來鍛煉自己的前端技能,還是對頁面游戲開發(fā)感興趣,前端小游戲?qū)诙紩蔀槟愕淖罴堰x擇

Vue3通透教程【從零到一】(付費(fèi)) 歡迎來到Vue3通透教程!這個專欄旨在為大家提供全面的Vue3相關(guān)技術(shù)知識。如果你有一些Vue2經(jīng)驗(yàn),這個專欄都能幫助你掌握Vue3的核心概念和使用方法。我們將從零開始,循序漸進(jìn)地引導(dǎo)你構(gòu)建一個完整的Vue應(yīng)用程序。通過實(shí)際案例和練習(xí),你將學(xué)會如何使用Vue3的模板語法、組件化開發(fā)、狀態(tài)管理、路由等功能。我們還會介紹一些高級特性,如Composition API和Teleport等,幫助你更好地理解和應(yīng)用Vue3的新特性。在這個專欄中,我們將以簡潔明了的步驟指導(dǎo)你完成每個項(xiàng)目,并提供詳細(xì)解釋和示例代碼。同時,我們也會分享一些Vue3開發(fā)中常見的問題和解決方案,幫助你克服困難并提升開發(fā)效率。無論你是想深入學(xué)習(xí)Vue3或者需要一個全面的指南來構(gòu)建前端項(xiàng)目,Vue3通透教程專欄都會成為你不可或缺的資源。

TypeScript入門指南(免費(fèi)) 是一個旨在幫助大家快速入門并掌握TypeScript相關(guān)技術(shù)的專欄。通過簡潔明了的語言和豐富的示例代碼,我們將深入講解TypeScript的基本概念、語法和特性。無論您是初學(xué)者還是有一定經(jīng)驗(yàn)的開發(fā)者,都能在這里找到適合自己的學(xué)習(xí)路徑。從類型注解、接口、類等核心特性到模塊化開發(fā)、工具配置以及與常見前端框架的集成,我們將全面覆蓋各個方面。通過閱讀本專欄,您將能夠提升JavaScript代碼的可靠性和可維護(hù)性,并為自己的項(xiàng)目提供更好的代碼質(zhì)量和開發(fā)效率。讓我們一起踏上這個精彩而富有挑戰(zhàn)性的TypeScript之旅吧!

 

藍(lán)藍(lán)設(shè)計(jì)(sillybuy.com )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的大數(shù)據(jù)可視化界面設(shè)計(jì)、B端界面設(shè)計(jì)桌面端界面設(shè)計(jì)、APP界面設(shè)計(jì)圖標(biāo)定制、用戶體驗(yàn)設(shè)計(jì)交互設(shè)計(jì)、UI咨詢、高端網(wǎng)站設(shè)計(jì)、平面設(shè)計(jì),以及相關(guān)的軟件開發(fā)服務(wù),咨詢電話:01063334945。

關(guān)鍵詞:UI咨詢、UI設(shè)計(jì)服務(wù)公司軟件界面設(shè)計(jì)公司、界面設(shè)計(jì)公司、UI設(shè)計(jì)公司、UI交互設(shè)計(jì)公司數(shù)據(jù)可視化設(shè)計(jì)公司、用戶體驗(yàn)公司、高端網(wǎng)站設(shè)計(jì)公司

銀行金融軟件UI界面設(shè)計(jì)、能源及監(jiān)控軟件UI界面設(shè)計(jì)、氣象行業(yè)UI界面設(shè)計(jì)、軌道交通界面設(shè)計(jì)、地理信息系統(tǒng)GIS UI界面設(shè)計(jì)、航天軍工軟件UI界面設(shè)計(jì)醫(yī)療行業(yè)軟件UI界面設(shè)計(jì)、教育行業(yè)軟件UI界面設(shè)計(jì)企業(yè)信息化UI界面設(shè)計(jì)、軟件qt開發(fā)、軟件wpf開發(fā)、軟件vue開發(fā)

前端學(xué)習(xí)大綱

前端達(dá)人

第一階段:

  • HTML+CSS:

HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、

  • JavaScript基礎(chǔ):

Js基礎(chǔ)教程、js內(nèi)置對象常用方法、常見DOM樹操作大全、ECMAscript、DOM、BOM、定時器和焦點(diǎn)圖。

  • JS基本特效:

常見特效、例如:tab、導(dǎo)航、整頁滾動、輪播圖、JS制作幻燈片、彈出層、手風(fēng)琴菜單、瀑布流布局、滾動事件、滾差視圖。

  • JS高級特征:

正則表達(dá)式、排序算法、遞歸算法、閉包、函數(shù)節(jié)流、作用域鏈、基于距離運(yùn)動框架、面向?qū)ο蠡A(chǔ)、

  • JQuery:基礎(chǔ)使用

懸著器、DOM操作、特效和動畫、方法鏈、拖拽、變形、JQueryUI組件基本使用。

第二階段:HTML5和移動Web開發(fā)

  • HTML5:

HTML5新語義標(biāo)簽、HTML5表單、音頻和視頻、離線和本地存儲、SVG、Web Socket、Canvas.

  • CSS3:

CSS3新選擇器、偽元素、臉色表示法、邊框、陰影、background系列屬性改變、Transition、動畫、景深和深透、3D效果制作、Velocity.js框架、元素進(jìn)場、出場策略、炫酷CSS3網(wǎng)頁制作。

  • Bootstrap:

響應(yīng)式概念、媒體查詢、響應(yīng)式網(wǎng)站制作、刪格系統(tǒng)、刪格系統(tǒng)原理、Bootstrap常用模板、LESS和SASS。

  • 移動Web開發(fā):

跨終端WEB和主流設(shè)備簡介、視口、流式布局、彈性盒子、rem、移動終端JavaScript事件、手機(jī)中常見JS效果制作、Zepto.js、手機(jī)聚劃算頁面、手機(jī)滾屏。

第三階段:HTTP服務(wù)和AJAX編程

  • WEB服務(wù)器基礎(chǔ):

服務(wù)器基礎(chǔ)知識、Apache服務(wù)器和其他WEB服務(wù)器介紹、Apache服務(wù)器搭建、HTTP介紹。

  • PHP基礎(chǔ):

PHP基礎(chǔ)語法、使用PHP處理簡單的GET或者POST請求、

  • AJAX上篇:

Ajax簡介和異步的概念、Ajax框架的封裝、XMLHttpRequest對象詳細(xì)介紹方法、兼容性處理方法、Ajax框架的封裝、Ajax中緩存問題、XML介紹和使用。

  • AJAX下篇:

JSON和JSON解析、數(shù)據(jù)綁定和模板技術(shù)、JSONP、跨域技術(shù)、圖片預(yù)讀取和lazy-load技術(shù)、JQuery框架中的AjaxAPI、使用Ajax實(shí)現(xiàn)爆布流案例額。

第四階段:面向?qū)ο筮M(jìn)階

  • 面向?qū)ο蠼K極篇:

從內(nèi)存角度到理解JS面向?qū)ο蟆⒒绢愋?、?fù)雜類型、原型鏈、ES6中的面向?qū)ο?、屬性讀寫權(quán)限、設(shè)置器、訪問器。

  • 面向?qū)ο笕筇卣鳎?/li>

繼承性、多態(tài)性、封裝性、接口。

  • 設(shè)計(jì)模式:

面向?qū)ο缶幊趟季S、單例模式、工廠模式、策略模式、觀察者模式、模板方法模式、代理模式、裝飾者模式、適配器模式、面向切面編程。

第五階段:封裝一個屬于自己的框架

  • 框架封裝基礎(chǔ):

事件流、冒泡、捕獲、事件對象、事件框架、選擇框架。

  • 框架封裝中級:

運(yùn)動原理、單物體運(yùn)動框架、多物體運(yùn)動框架、運(yùn)動框架面向?qū)ο蠓庋b。

  • 框架封裝高級和補(bǔ)充:

JQuery框架雛形、可擴(kuò)展性、模塊化、封裝屬于傳智自己的框架。

第六階段:模塊化組件開發(fā)

  • 面向組件編程:

面向組件編程的方式、面向組件編程的實(shí)現(xiàn)原理、面向組件編程實(shí)戰(zhàn)、基于組件化思想開發(fā)網(wǎng)站應(yīng)用程序。

  • 面向模塊編程:

AMD設(shè)計(jì)規(guī)范、CMD設(shè)計(jì)規(guī)范、RequireJS,LoadJS、淘寶的SeaJS。

第七階段:主流的流行框架

  • Web開發(fā)工作流:

GIT/SVN、Yeoman腳手架、NPM/Bower依賴管理工具、Grunt/Gulp/Webpack。

  • MVC/MVVM/MVW框架:

Angular.js、Backbone.js、Knockout/Ember。

  • 常用庫:

React.js、Vue.js、Zepto.js。

第八階段:HTML5原生移動應(yīng)用開發(fā)

  • Cordova:

WebApp/NativeApp/HybirdApp簡介、Cordova簡介、與PhoneGap之間的關(guān)系、開發(fā)環(huán)境搭建、Cordova實(shí)戰(zhàn)(創(chuàng)建項(xiàng)目,配置,編譯,調(diào)試,部署發(fā)布)。

  • Ionic:

Ionic簡介和同類對比、模板項(xiàng)目解析、常見組件及使用、結(jié)合Angular構(gòu)建APP、常見效果(下拉刷新,上拉加載,側(cè)滑導(dǎo)航,選項(xiàng)卡)。

  • React Native:

React Native簡介、React Native環(huán)境配置、創(chuàng)建項(xiàng)目,配置,編譯,調(diào)試,部署發(fā)布、原生模塊和UI組件、原生常用API。

  • HTML5+:

HTML5+中國產(chǎn)業(yè)聯(lián)盟、HTML5 Plus Runtime環(huán)境、HBuilder開發(fā)工具、MUI框架、H5+開發(fā)和部署。

第九階段:   Node.js全棧開發(fā):

  • 快速入門:

Node.js發(fā)展、生態(tài)圈、Io.js、Linux/Windows/OS X環(huán)境配置、REPL環(huán)境和控制臺程序、異步編程,非阻塞I/O、模塊概念,模塊管理工具、開發(fā)流程,調(diào)試,測試。

  • 核心模塊和對象:

全局對象global,process,console,util、事件驅(qū)動,事件發(fā)射器、加密解密,路徑操作,序列化和反序列化、文件流操作、HTTP服務(wù)端與客戶端、Socket.IO。

  • Web開發(fā)基礎(chǔ):

HTTP協(xié)議,請求響應(yīng)處理過程、關(guān)系型數(shù)據(jù)庫操作和數(shù)據(jù)訪問、非關(guān)系型數(shù)據(jù)庫操作和數(shù)據(jù)訪問、原生的Node.js開發(fā)Web應(yīng)用程序、Web開發(fā)工作流、Node.js開發(fā)Blog案例。

  • 快速開發(fā)框架:

Express簡介+MVC簡介、Express常用API、Express路由模塊、Jade/Ejs模板引擎、使用Express重構(gòu)Blog案例、Koa等其他常見MVC框架。

  • Node.js開發(fā)電子商務(wù)實(shí)戰(zhàn):

需求與設(shè)計(jì)、賬戶模塊注冊登錄、會員中心模塊、前臺展示模塊、購物車,訂單結(jié)算、在線客服即時通訊模塊。

MacOS查找各Python版本的路徑

前端達(dá)人

MacOS自帶Python路徑為:/System/Library/Frameworks/Python.framework/Versions
自行安裝Python路徑為:/Library/Frameworks/Python.framework/Versions/
打開Terminal
切換工作路徑:cd /System/Library/Frameworks/Python.framework/Versions/current/bin
打印相對路徑Python版本:./python --version
打印當(dāng)前用戶Python版本:python --version

如下圖可以看到,系統(tǒng)Python版本為2.7,當(dāng)前用戶Python為3.7

 

使用which命令查看各版本Python的文件路徑

系統(tǒng)命令默認(rèn)路徑/usr/bin(系統(tǒng)預(yù)裝的可執(zhí)行文件,隨系統(tǒng)升級而變化)
用戶命令默認(rèn)路徑/usr/local/bin(用戶安裝的可執(zhí)行文件,不隨系統(tǒng)升級影響)
其中,usrUnix System Resource

可以看到/usr/bin中有python可執(zhí)行命令,其版本為2.7.18,而/usr/local/bin則沒有python,存放的是python3.7的執(zhí)行命令

 

在Mac電腦上安裝Python環(huán)境可以按照以下步驟進(jìn)行操作:

步驟1: 下載Python安裝包

訪問Python官方網(wǎng)站(https://www.python.org/downloads/macos/)下載適用于Mac的Python安裝包。根據(jù)你的操作系統(tǒng)版本選擇合適的安裝包,通常選擇最新的穩(wěn)定版本。
在這里插入圖片描述

步驟2: 運(yùn)行安裝包

雙擊下載的Python安裝包,會出現(xiàn)一個安裝向?qū)Т翱凇|c(diǎn)擊"Continue"繼續(xù)安裝。
在這里插入圖片描述

步驟3: 配置安裝選項(xiàng)

在安裝向?qū)Т翱谥校梢赃x擇安裝Python的位置和其他可選組件。通常建議保持默認(rèn)設(shè)置,然后點(diǎn)擊"Install"開始安裝。

步驟4: 輸入管理員密碼

安裝過程中,系統(tǒng)可能會要求輸入管理員密碼。輸入密碼并點(diǎn)擊"Install Software"繼續(xù)安裝。

步驟5: 等待安裝完成

安裝過程可能需要一些時間,請耐心等待直到安裝完成。

步驟6: 驗(yàn)證安裝結(jié)果

安裝完成后,打開終端應(yīng)用程序(Terminal),輸入以下命令驗(yàn)證Python安裝是否成功:

python3 -V
  • 1

如果成功安裝,終端會顯示Python的版本號。

 

產(chǎn)品經(jīng)理如何與工程師合作?我總結(jié)了4個方面?。本┧{(lán)藍(lán)UI設(shè)計(jì)公司

周周

在產(chǎn)品線或者項(xiàng)目組中,開發(fā)工程師絕對是最大的群體,包含前端開發(fā)、后端開發(fā)、測試等崗位。之前做交互設(shè)計(jì)師時,跟開發(fā)人員直接的溝通并不多,主要在交互設(shè)計(jì)宣講和還原度測試時有些接觸。即使有些糾纏,也會通過產(chǎn)品經(jīng)理進(jìn)行協(xié)調(diào),溝通的難度并不大。轉(zhuǎn)崗產(chǎn)品經(jīng)理后,主要溝通對象就變成了開發(fā)工程師。今天來聊聊我遇到過或合作過的“開發(fā)大佬”們。

干貨!四個章節(jié)深度解析「組件」知識點(diǎn)|蘭亭妙微UI設(shè)計(jì)公司

資深UI設(shè)計(jì)者

干貨!四個章節(jié)深度解析「組件」知識點(diǎn)|蘭亭妙微UI設(shè)計(jì)公司


第一章:組件的定義和基本概念
在軟件開發(fā)領(lǐng)域,組件是指獨(dú)立的、可重用的軟件模塊,它們具有特定的功能和接口,可以被組合成更大的軟件系統(tǒng)。組件可以是軟件對象、類、庫、模塊或其他單位。它們通過定義輸入和輸出接口,以及實(shí)現(xiàn)特定功能來提供服務(wù)。
組件的基本概念包括以下幾個方面:
1.1 組件容器:組件容器是一個環(huán)境,用于加載、管理和執(zhí)行組件。容器提供對組件的生命周期管理、通信和部署支持。組件容器可以是運(yùn)行時環(huán)境(如操作系統(tǒng)、應(yīng)用服務(wù)器)或特定的框架(如Java EE容器、ASP.NET容器)。
1.2 組件接口:組件接口定義了組件對外提供的服務(wù)和合約。它包括輸入?yún)?shù)、輸出結(jié)果以及可能的異常。接口可以通過編程語言的接口、類、方法或其他機(jī)制來定義。
1.3 組件協(xié)作:組件可以通過協(xié)作來完成更復(fù)雜的任務(wù)。協(xié)作可以通過組件之間的接口調(diào)用、事件觸發(fā)、消息傳遞等方式進(jìn)行。協(xié)作可以實(shí)現(xiàn)任務(wù)的拆分、并行處理和功能擴(kuò)展。
1.4 組件復(fù)用:組件的重要特性是可復(fù)用性。組件的設(shè)計(jì)和實(shí)現(xiàn)應(yīng)該考慮到復(fù)用的需求,使其可以在不同的上下文中被重復(fù)使用。組件復(fù)用可以提高開發(fā)效率、降低維護(hù)成本,并促進(jìn)軟件系統(tǒng)的生態(tài)系統(tǒng)發(fā)展。
第二章:組件化開發(fā)和架構(gòu)模式
2.1 組件化開發(fā):組件化開發(fā)是一種軟件開發(fā)方法,通過將軟件系統(tǒng)劃分為獨(dú)立的組件來提高開發(fā)效率和質(zhì)量。組件化開發(fā)促進(jìn)了模塊化、可復(fù)用、可測試和可維護(hù)的代碼編寫。它還鼓勵團(tuán)隊(duì)協(xié)作和并行開發(fā)。
2.2 組件化架構(gòu)模式:組件化架構(gòu)模式是一種組織和管理組件的方式。常見的組件化架構(gòu)模式包括面向服務(wù)架構(gòu)(SOA)、微服務(wù)架構(gòu)和組件協(xié)作模式等。這些架構(gòu)模式通過定義組件之間的接口、通信和協(xié)議,實(shí)現(xiàn)了松耦合、可擴(kuò)展和可替換的軟件系統(tǒng)。

第三章:組件的優(yōu)勢和挑戰(zhàn)
3.1 組件的優(yōu)勢:組件化開發(fā)具有許多優(yōu)勢。首先,它提供了代碼重用和模塊化的機(jī)制,減少了開發(fā)工作量和維護(hù)成本。其次,組件可以提供標(biāo)準(zhǔn)化的接口,促進(jìn)了團(tuán)隊(duì)協(xié)作和模塊復(fù)用。此外,組件可以獨(dú)立測試和部署,提高了系統(tǒng)的可靠性和可擴(kuò)展性。
3.2 組件的挑戰(zhàn):盡管組件化開發(fā)具有許多優(yōu)勢,但也存在一些挑戰(zhàn)。首先,組件的設(shè)計(jì)和實(shí)現(xiàn)需要額外的工作和時間。其次,組件之間的協(xié)作和通信涉及到復(fù)雜的依賴關(guān)系和調(diào)試過程。此外,組件的版本管理和升級可能導(dǎo)致一些兼容性和穩(wěn)定性的問題。
第四章:組件化開發(fā)實(shí)踐和案例分析
4.1 組件化開發(fā)實(shí)踐:組件化開發(fā)需要結(jié)合具體的技術(shù)和工具來實(shí)現(xiàn)。常見的組件化開發(fā)實(shí)踐包括使用面向?qū)ο缶幊?、設(shè)計(jì)模式、依賴注入和模塊化打包工具等。此外,組件化開發(fā)還需要規(guī)范和標(biāo)準(zhǔn)來指導(dǎo)開發(fā)和集成。
4.2 組件化開發(fā)案例分析:組件化開發(fā)已經(jīng)在軟件開發(fā)領(lǐng)域得到廣泛應(yīng)用。例如,Android開發(fā)中的組件化架構(gòu)、Java EE中的Enterprise JavaBean、.NET中的組件模型等。這些案例提供了關(guān)于組件化開發(fā)的實(shí)踐經(jīng)驗(yàn)和最佳實(shí)踐。

藍(lán)藍(lán)設(shè)計(jì),工作室2008年開始,2011年正式成立北京蘭亭妙微科技有限公司,主創(chuàng)清華團(tuán)隊(duì),專注軟件和互聯(lián)網(wǎng)ui設(shè)計(jì)開發(fā)。擅長企業(yè)信息化管理、監(jiān)控、大數(shù)據(jù)軟件UIUE咨詢和設(shè)計(jì)開發(fā)服務(wù)。立足UI,一直在學(xué)習(xí)進(jìn)步。
藍(lán)藍(lán)設(shè)計(jì),秉承設(shè)計(jì)優(yōu)秀,不斷超越的理念,誠信敬業(yè)、專業(yè)耐心的工作作風(fēng),進(jìn)行設(shè)計(jì)服務(wù)創(chuàng)新,幫助企業(yè)進(jìn)行軟件和互聯(lián)網(wǎng)產(chǎn)品的界面設(shè)計(jì)及開發(fā)升級,提供卓越的解決方案。對軟件界面用戶體驗(yàn)與交互設(shè)計(jì)與實(shí)現(xiàn),國際化標(biāo)準(zhǔn)和流行趨勢,進(jìn)行不斷的研究和實(shí)踐,擁有豐富的解決問題經(jīng)驗(yàn)。

讓用戶輸密碼的正確姿勢!簡化密碼設(shè)計(jì)的三個小秘籍

資深UI設(shè)計(jì)者

讓用戶輸密碼的正確姿勢!簡化密碼設(shè)計(jì)的三個小秘籍

2023-06-28 15:50北京北京蘭亭妙微科技有限公司官方帳號

隨著互聯(lián)網(wǎng)的普及和數(shù)字化時代的來臨,密碼的重要性不言而喻。然而,很多人在設(shè)計(jì)密碼時往往面臨記憶難題和安全性問題。為了幫助用戶設(shè)計(jì)更簡化且安全的密碼,本文將介紹三個小秘籍。

一、使用密碼管理工具

密碼管理工具是一種方便且安全的方式來管理和存儲密碼。它們通常提供加密的存儲空間,可以儲存各種賬戶的用戶名和密碼。用戶只需記住一個主密碼,就能夠訪問和管理所有其他密碼。這樣,用戶可以選擇更復(fù)雜、更安全的密碼,而不必?fù)?dān)心記憶的問題。此外,密碼管理工具通常還提供自動生成密碼的功能,確保密碼的隨機(jī)性和安全性。一些常見的密碼管理工具包括LastPass、1Password和Keepass等。

二、使用短語或句子作為密碼

傳統(tǒng)的密碼通常由字符、數(shù)字和特殊符號組成,很難記憶且容易被猜測。相比之下,使用短語或句子作為密碼可以更容易記住且更安全。選擇一個有意義的短語或句子,并將其轉(zhuǎn)化為密碼。例如,"ILoveToTravelTheWorld!",這個短語可以轉(zhuǎn)化為密碼"Ilv2ttw!"。這樣的密碼不僅容易記憶,而且由于包含了大小寫字母、數(shù)字和特殊符號,具備了一定的安全性。

三、使用多因素身份驗(yàn)證

多因素身份驗(yàn)證是一種提高賬戶安全性的重要方式。除了使用密碼外,多因素身份驗(yàn)證要求用戶提供第二個驗(yàn)證因素,如手機(jī)驗(yàn)證碼、指紋識別或硬件安全密鑰等。這樣,即使密碼被泄露,黑客也無法輕易訪問賬戶。許多在線服務(wù)提供了多因素身份驗(yàn)證選項(xiàng),用戶應(yīng)該積極開啟并使用這個功能。

綜上所述,設(shè)計(jì)簡化且安全的密碼并不是一件困難的事情。通過使用密碼管理工具、使用短語或句子作為密碼以及使用多因素身份驗(yàn)證,用戶可以更好地保護(hù)自己的賬戶安全。重要的是,用戶應(yīng)該時刻保持警惕,定期更換密碼,并避免在多個賬戶中使用相同的密碼,以確保個人信息的安全。

今日分享這篇文章是藍(lán)藍(lán)設(shè)計(jì)的原創(chuàng)文章,未來將會持續(xù)在平臺上分享關(guān)于設(shè)計(jì)行業(yè)的文章。此外藍(lán)藍(lán)設(shè)計(jì)建立了UI設(shè)計(jì)分享群,每天會分享國內(nèi)外的一些優(yōu)秀設(shè)計(jì),如果有興趣的話,可以進(jìn)入一起成長學(xué)習(xí),添加vx藍(lán)小助ben_lanlan,報(bào)下信息,藍(lán)小助會請您入群。同時添加藍(lán)小助我們將會為您提供優(yōu)秀的設(shè)計(jì)案例和設(shè)計(jì)素材等,歡迎您加入噢~~希望得到建議咨詢、商務(wù)合作,也請與我們聯(lián)系。

藍(lán)藍(lán)設(shè)計(jì)( sillybuy.com )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)、UI設(shè)計(jì)公司、界面設(shè)計(jì)公司、UI設(shè)計(jì)服務(wù)公司、數(shù)據(jù)可視化設(shè)計(jì)公司、UI交互設(shè)計(jì)公司、高端網(wǎng)站設(shè)計(jì)公司、UI咨詢、用戶體驗(yàn)公司、軟件界面設(shè)計(jì)公司

js谷歌地圖 根據(jù)國家添加不同的點(diǎn)擊事件

前端達(dá)人

以下是在 JavaScript 和 Google 地圖 API 中添加點(diǎn)擊事件,根據(jù)國家進(jìn)行不同操作的示例代碼:


//創(chuàng)建地圖對象
var map = new google.maps.Map(document.getElementById('map'), {
  zoom: 4,
  center: {lat: 37.0902, lng: -95.7129}
});

//創(chuàng)建信息窗口(infowindow)
var infowindow = new google.maps.InfoWindow();

//創(chuàng)建一個數(shù)組來存儲標(biāo)記
var markers = [];

//為每個國家添加點(diǎn)擊事件
google.maps.event.addListener(map, 'click', function(event) {
  //獲取點(diǎn)擊位置的經(jīng)緯度坐標(biāo)
  var latLng = event.latLng;

  //使用地理編碼器(geocoder)將經(jīng)緯度坐標(biāo)轉(zhuǎn)換為地址信息
  var geocoder = new google.maps.Geocoder();
  geocoder.geocode({'location': latLng}, function(results, status) {
    if (status === 'OK') {
      if (results[0]) {
        //獲取點(diǎn)擊位置所在的國家名稱
        var countryName = '';
        for (var i = 0; i < results[0].address_components.length; i++) {
          var component = results[0].address_components[i];
          if (component.types.indexOf('country') !== -1) {
            countryName = component.long_name;
            break;
          }
        }

        //根據(jù)國家名稱執(zhí)行相應(yīng)操作
        switch (countryName) {
          case 'China':
            alert('您點(diǎn)擊了中國');
            break;
          case 'United States':
            alert('您點(diǎn)擊了美國');
            break;
          default:
            alert('您點(diǎn)擊了' + countryName);
        }

        //創(chuàng)建標(biāo)記并將其添加到地圖上
        var marker = new google.maps.Marker({
          position: latLng,
          map: map
        });

藍(lán)藍(lán)設(shè)計(jì)建立了UI設(shè)計(jì)分享群,每天會分享國內(nèi)外的一些優(yōu)秀設(shè)計(jì),如果有興趣的話,可以進(jìn)入一起成長學(xué)習(xí),請加微信ban_lanlan,報(bào)下信息,藍(lán)小助會請您入群。歡迎您加入噢~~ 希望得到建議咨詢、商務(wù)合作,也請與我們聯(lián)系01063334945。  分享此文一切功德,皆悉回向給文章原作者及眾讀者. 免責(zé)聲明:藍(lán)藍(lán)設(shè)計(jì)尊重原作者,文章的版權(quán)歸原作者。如涉及版權(quán)問題,請及時與我們?nèi)〉寐?lián)系,我們立即更正或刪除。  藍(lán)藍(lán)設(shè)計(jì)sillybuy.com )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)、UI設(shè)計(jì)公司、界面設(shè)計(jì)公司、UI設(shè)計(jì)服務(wù)公司、數(shù)據(jù)可視化設(shè)計(jì)公司、UI交互設(shè)計(jì)公司、高端網(wǎng)站設(shè)計(jì)公司、UI咨詢、用戶體驗(yàn)公司、軟件界面設(shè)計(jì)公司。 

日歷

鏈接

個人資料

存檔