iT邦幫忙

1

<解決>js變數問題

  • 分享至 

  • xImage

宣告了一個全域變數img
在function內要將dataUrl存取給img,用console.log檢查卻無變化,想請教原因及方法

<body>
    <div id="capture" style="padding: 10px; background: #f5da55">
        <h4 style="color: #000; ">Hello world!</h4>
    </div>
    <button onclick="block_capture()">點我擷取區塊</button>
    <script>
     /*https://stackoverflow.com/questions/6150289/how-can-i-convert-an-image-into-base64-string-using-javascript*/   

        var img="6";

        function DataURL(url, callback) {
          var xhr = new XMLHttpRequest();
          xhr.onload = function() {
            var reader = new FileReader();
            reader.onloadend = function() {
              callback(reader.result);
            }
            reader.readAsDataURL(xhr.response);
          };
          xhr.open('GET', url);
          xhr.responseType = 'blob';
          xhr.send();
        }

        function block_capture() {
            html2canvas(document.querySelector("#capture")).then(function (canvas) {
                a = document.createElement('a');
                a.href = canvas.toDataURL("image/jpeg", 0.92).replace("image/jpeg", "image/octet-stream");
                a.download = 'image.jpg';
                //a.click();
                DataURL(a, function(dataUrl) {
                console.log('RESULT:', dataUrl);
                img=dataUrl;                            
                })                
            });
        }
        console.log("IMAGEBASE:",img);

    </script>

</body>

https://ithelp.ithome.com.tw/upload/images/20210807/20133915qxcJRMaVam.png

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

1
淺水員
iT邦大師 6 級 ‧ 2021-08-07 14:16:16
最佳解答

主要的原因在於 XMLHttpRequest、FileReader 讀資料都是非同步執行的
(可以搜尋「JS 非同步」或「JS 異步」相關的文章了解一下)

簡單的解決方式是把 console.log("IMAGEBASE:",img); 挪到 callback 裡面
也就是

function block_capture() {
    html2canvas(document.querySelector("#capture")).then(function (canvas) {
        a = document.createElement('a');
        a.href = canvas.toDataURL("image/jpeg", 0.92).replace("image/jpeg", "image/octet-stream");
        a.download = 'image.jpg';
        //a.click();
        DataURL(a, function (dataUrl) {
            console.log('RESULT:', dataUrl);
            img = dataUrl;
            console.log("IMAGEBASE:",img); //挪到這邊
        })
    });
}

除了 callback 之外,也可以了解一下其他處理方法

看更多先前的回應...收起先前的回應...
0805cyc iT邦新手 4 級 ‧ 2021-08-07 14:31:57 檢舉

您好~謝謝您的回覆
那想試問若把console.log("IMAGEBASE:",img); 挪到 callback 裡面後
將全域變數img 給php 的話
這樣是會顯示更改過後的資料嗎?

淺水員 iT邦大師 6 級 ‧ 2021-08-07 14:34:59 檢舉

剛剛我再細看,DataURL 函式目前看來是多餘的
因為 canvas.toDataURL("image/jpeg", 0.92) 本身就是 dataurl 了,不用再透過 DataURL 函式轉換
另外改成 image/octet-stream 應該也是沒必要的行為
所以這樣寫就可

function block_capture() {
    html2canvas(document.querySelector("#capture")).then(function (canvas) {
        let dataUrl = canvas.toDataURL("image/jpeg", 0.92);
        console.log('RESULT:', dataUrl);
        img = dataUrl;
        console.log("IMAGEBASE:", img);
    });
}
淺水員 iT邦大師 6 級 ‧ 2021-08-07 14:38:04 檢舉

將全域變數img 給php 的話
這樣是會顯示更改過後的資料嗎?

你是要把圖片傳給 php 嗎?
如果是的話:

  1. 你 php 接收圖片的程式碼在哪?
  2. javascript 傳資料給 php 的程式碼在哪?

這樣是會顯示更改過後的資料嗎?

這邊你是希望只有在瀏覽器這邊顯示,還是先存到伺服器資料庫後再顯示到瀏覽器?

0805cyc iT邦新手 4 級 ‧ 2021-08-07 17:52:21 檢舉

是的,我是要把圖片傳給 php
主要想用表單提交的方式傳到mysql資料庫(不用顯示到瀏覽器)
但目前遇到的問題是在input外包form表單的話
document.getElementById("test").value = img;
這句是沒有效果的(input內沒有值)
若拿掉form的話input內是有值的

divimage.php程式

<body>
    <div id="capture" style="padding: 10px; background: #f5da55">
        <h4 style="color: #000; ">Hello world!</h4>
    </div>
    <form action="" method="post">
        <input type="text" id="test" name="test"/>
        <button id="sub" onclick="block_capture()">點我擷取區塊</button>
    </form>
    <script>
     /*https://stackoverflow.com/questions/6150289/how-can-i-convert-an-image-into-base64-string-using-javascript*/   

     var img="5";

     function block_capture() {
        html2canvas(document.querySelector("#capture")).then(function (canvas) {
            let dataUrl = canvas.toDataURL("image/jpeg", 0.92);
            console.log('RESULT:', dataUrl);
            img = dataUrl;
            console.log("IMAGEBASE:", img);

            document.getElementById("test").value = img;
            });
     }

    </script>

</body>
    <?php
        require_once("connMysql.php");

        if(isset($_POST['sub'])){
        $test = $_POST['test'];

        //執行 SQL 命令,新增此帳號
        $sql = "INSERT INTO div_image (Divimage) 
          VALUES ('$test')";

        $db_link->query($sql);

        //關閉資料連接  
        $db_link->close();
        }   
    ?>
淺水員 iT邦大師 6 級 ‧ 2021-08-07 20:03:56 檢舉

我可能會用 FormData 傳資料
再依據 php 處理後的回應採取其他動作
大概如下

function block_capture() {
    html2canvas(document.querySelector("#capture")).then(function (canvas) {
        //把 canvas 轉成 blob
        return new Promise(resolve => {
            canvas.toBlob(resolve, "image/jpeg", 0.92);
        });
    }).then(blob => {
        //用 FormData 傳送到伺服器
        let fd = new FormData;
        fd.append('capture', blob);
        return fetch('reciver.php', {
            method: 'post',
            body: fd
        }).then(response => {
            if (response.status !== 200) {
                return Promise.reject(`上傳失敗(${response.statusText})`);
            }
            //上傳成功
            return response.json();
        }).then(json => {
            //顯示訊息
            console.log(json);
            alert('上傳成功');
        }).catch(e => {
            alert(e);
        });
    });
}

接收資料的 php

<?php
if (!isset($_FILES['capture'])) {
    http_response_code(400);
    exit();
}

//產生一個獨立的檔名,用來儲存圖片
//這邊只是作範例,簡單用 uniqid ,實際上應該更嚴謹
$filename = uniqid() . '.jpg';

//把暫存檔移動到指定檔名
move_uploaded_file($_FILES['capture']['tmp_name'], $filename);

//之後可以把圖片的檔名儲存到資料庫(這邊省略)

//回傳想要回應的訊息,這邊我是把檔名回傳,也可以帶其他資料
echo json_encode([
    'file' => $filename,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
0805cyc iT邦新手 4 級 ‧ 2021-08-08 13:48:24 檢舉

謝謝您用心提供的解決方式
小女子對json沒有很了解也不熟悉..@@"
我會當作參考的!真的很不好意思

我要發表回答

立即登入回答