打開小程式的大門---一款天氣小程式的誕生(蝸牛小天氣)

来源:https://www.cnblogs.com/lcy-snail/archive/2019/03/22/10576762.html
-Advertisement-
Play Games

———— 潤物無聲,做一個有個格調的coder 小程式、快應用 現在可謂是家喻戶曉,也更加密切的滲透入我們的生活中,筆者也算是個愛折騰的人,俗話說的好嘛,“不折騰,不前端“(當然是筆者自己的小心聲)。於是在平日里忙碌的工作之餘抽出來時間搞點事(si)情,來寫一個屬於自己的貼身小天氣。說時遲那時快,這 ...


———— 潤物無聲,做一個有個格調的coder

小程式、快應用現在可謂是家喻戶曉,也更加密切的滲透入我們的生活中,筆者也算是個愛折騰的人,俗話說的好嘛,“不折騰,不前端“(當然是筆者自己的小心聲)。於是在平日里忙碌的工作之餘抽出來時間搞點事(si)情,來寫一個屬於自己的貼身小天氣。說時遲那時快,這就來了...

經過兩三年的發展,小程式的地位也步步高升,由騰訊領隊的騰訊小程式,再到後來的支付寶,美團,頭條等也都相應推出自家的小程式平臺,都想順著潮流抓住流量分一杯羹,可謂是兵家必爭之地。大環境的改變,為了提高小程式的快速迭代和多人合作開發的效率,也使得各大廠商都開源了自己的小程式框架,mpvuewepyMINATaro等相信大家也比較熟悉了。而小程式的社區也變得跟豐富健壯,也衍生出很多精美的UI框架。有興趣的可以自行去相應的官網瞭解詳情。

雖然上面介紹了那麼多的框架,而本次筆者並沒有使用框架,而是用原生的小程式來開發今天的主角,也希望能夠用原始的方式來給那些和筆者一樣的剛剛入門的小程式開發者一些幫助,也將自己所學的記錄下來。畢竟原生才是最底層的基礎,所有的框架都是在原生的基礎上開花結果的,這樣才能以不變應萬變(吼吼~)。筆者水平有限,有錯誤或者解釋不當的地方還望各位看官多多包涵。

蝸牛小天氣 效果圖

項目源碼 潤物無聲github

預覽圖
預覽圖1

概況

二維碼

在定位功能中,本程式用到騰訊地圖的api
相應的天氣介面中,本程式用到的是和風天氣提供的api

兩者都需要到官網中註冊開發者賬號,通過註冊後得到的appKey來請求我們需要的數據,詳細註冊步驟請自行度娘

由於需要用到定位功能,而小程式本身的getLocation方法獲取到的是當前位置的坐標:

    wx.getLocation({
      type: 'gcj02', // 返回坐標的格式
      success: res => {
          // 此處只能獲取到當前位置的經緯度(坐標)
      },
    })

所以需要利用騰訊地圖Api,通過坐標點反向獲得該地點的詳細信息。

基本配置

在app.json中是對整個小程式的一些基本配置

    {
    "pages": [
        "pages/index/index" // 當前小程式的主入口頁面
    ],
    // 主視窗的一些配置,如下,對背景顏色和小程式頂部的導航欄的樣式進行了配置
    "window": {
        "backgroundColor": "#A7CAD3", 
        "backgroundTextStyle": "dark",
        "navigationBarBackgroundColor": "#A7CAD3",
        "navigationBarTitleText": "蝸牛天氣",
        "navigationBarTextStyle": "black",
        "navigationStyle":"custom"
    },
    "permission": {
        "scope.userLocation": {
        "desc": "蝸牛天氣嘗試獲取您的位置信息" // 詢問用戶是否可以得到獲取位置許可權的提示文字
        }
    }
}

接下來,我們就來一步一步的實現這個小程式吧~~

1.界面

由於沒有UI,再加上筆者扭曲的審美能力(坐在屏幕前開始愣神,陷入沉思...),所以還望各位看官多忍耐筆者又想又借鑒的界面成果...看來以後要多加強這方面的能力(haha~)

好了言歸正傳,首先,準備用一個頁面來解決戰鬥,那就是各位看到以上的這個頁面(都說了是‘小天氣’嘛),頁面一共分為五個部分,實時天氣、24小時內天氣情況、未來一星期內天氣情況、今天日落日出風向降雨等相關信息和天氣的生活指數,這五個部分組成了整個頁面,其對應的相應佈局見一下代碼

<view class="container" style='background: url({{bgImgUrl}}) center -200rpx / 100% no-repeat #62aadc;'>
    <view style='margin-top: -150rpx; padding-top: 150rpx;background: rgba(52,73,94, {{apl}})'>
      <view class='animation-view'>
      <!-- 當前定位信息顯示 -->
        <view class='location' bind:tap="chooseLocation">
          <myicon class="icon" type="dingwei"></myicon>
          <text class='city'>{{position}}</text>
        </view>
        <!-- 通過canvas畫出當前天氣情況動畫 -->
        <canvas canvas-id='animation' ></canvas>
        <!-- 實時天氣情況 -->
        <view class="center-container">
        ...  
        </view>
        <!-- 24小時內天氣情況 -->
        <view class="all-day-list">
          <scroll-view class="scroll-view_x" scroll-x>
            <view class="all-day-list-item" wx:for="{{everyHourData}}" wx:key="item.time">
              <view class="day-list-item">{{item.time}}點</view>
              <view class="day-list-item">
                <myicon type="{{item.iconType}}"></myicon>
              </view>
              <view class="day-list-item">{{item.tmp}}°</view>
            </view>
          </scroll-view>
        </view>
      </view>
        <!-- 一星期內天氣 -->
      <view class="one-week-list">
        <view class="one-week-list-item" wx:for="{{everyWeekData}}" wx:key="item.weekday">
          <view class="week-list-item">
            <view>{{item.weekday}}</view>
            <view>{{item.date}}</view>
          </view>
          <view class="week-list-item">{{item.cond_txt_d}}</view>
          <view class="week-list-item">
            <myicon type="{{item.iconTypeBai}}"></myicon>
          </view>
          <view class="week-list-item">{{item.tmp_min}}~{{item.tmp_max}}°</view>
          <view class="week-list-item">
            <myicon type="{{item.iconTypeYe}}"></myicon>
          </view>
          <view class="week-list-item">{{item.cond_txt_n}}</view>
          <view class="week-list-item" style="font-size: 28rpx">
            <view>{{item.wind_dir == '無持續風向' ? '無' : item.wind_dir}}</view>
            <view>{{item.wind_sc}}級</view>
          </view>
        </view>

      </view>
        <!-- 日出日落風向降雨概率等 -->
      <view class='live-index-view'>
        ...
      </view>
        <!-- 生活指數 -->
      <view class='last-view'>
        <view class='last-view-item' wx:for="{{lifeStyle}}" wx:key="item.type">
          <view class='last-view-item-top'>{{lifeEnum[item.type]}}</view>
          <view class='last-view-item-bottom'>{{item.brf}}</view>
        </view>
      </view>
    </view>
</view>

具體 css 樣式,詳見 蝸牛小天氣 源碼

註意:(筆者入坑,一開始使用的縱向的scroll-view,後來無奈的用了原來頁面的滾動)
scroll-view: 具體屬性參考小程式官方文檔
在小程式中,內部為我們提供了scroll-view這個頁面滾動的組件,對性能進行了一些優化,方便我們的使用。與此同時,也會有一些小坑

  • 在使用scroll-view是,如果是縱向(Y軸)滾動,scroll-y屬性,則必須為此scroll-view設置一個固定(明確)的高
  • 請勿在scroll-view組件標簽內使用 textarea、map、canvas、video等組件
  • 在使用了scroll-view組件時會阻止頁面的回彈效果,也就是在scroll-view中滾動,無法觸發onPullDownRefresh方法
  • 如果想使用原生的下拉刷新(非自定義)或者雙擊頂部頁面回滾到頁面頂部,請不要使用scroll-view。

相信各位看官發現了以上代碼中有一個<myicon> 的標簽,此標簽為一個圖標組件,因為蝸牛天氣中用到的圖標也比較多。接下來我們說明下有關組件的封裝事宜。為了提高代碼的復用性和易維護性,以及多人合作開發的效率,組件化似乎是一個很好的解決辦法,在微信小程式中,每個頁面由四個文件組成

  • *.wxml ----文檔結構 => 等同於html
  • *.js ----處理業務邏輯
  • *.json ----當前頁面或組件的一些配置和選項
  • *.wxss ----樣式文件 => 等同於css

而對於本小程式中<myicon>組件來說

<!-- 僅有一個text標簽,通過type屬性來改變字元圖標的類型(多雲,小雨...) -->
<!-- 字元圖標通過css樣式和自定義字體來實現,通過class來顯示不同類型的圖標字體 -->
<!-- 具體自定義字體圖標製作過程可參考此鏈接 https://blog.csdn.net/thatway_wp/article/details/79076023 -->
<text class="icon icon-{{type}}"></text>
// 小程式中的組件,通過調用Component方法,將組件的邏輯處理部分,屬性以及方法(生命周期)等一對象的方式傳入Component方法中
Component({
    properties: {
      type: {
        type: String, // type屬性的類型
        value: '' // 預設值
      }
    }
  });

使用了Component構造器,通過參數指定組件的屬性,數據,方法以及生命周期中的一些方法,在此組件中定義了接受的type屬性,類型為字元串,其預設值為空字元串。

{
    "component": true // 配置,當前為組件
}
// CSS 部分略過...

就這樣,一個簡單的icon圖標組件就封裝好了,是不是很簡單啊。封裝是封裝好了,那麼我們怎麼調用這個組件呢,是不是很類似於Vue呢,沒錯,只需要在你調用的頁面中註冊一下即可

// 當前想要調用的頁面的*.json文件中,如下
{
  "enablePullDownRefresh": true, // 此項與組件無關,此項為是否用小程式本身的下拉刷新功能
  "usingComponents": {
    "myicon": "../../components/icon/index" // 調用,註冊icon組件
  }
}

2.相關數據API

一開始就說到了需要使用騰訊地圖API的appkey還有和風天氣API的appkey,筆者是將appkey配置在了config.js中,看官只需將自己相應的appkey值替換即可,由於appkey是私密的,此處就不公開了,還望諒解。

// config.js
export default {
    MAP_API_KEY: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', // 騰訊地圖key
    WEATHER_API_KEY: 'XXXXXXXXXXXXXXXX' // 和風天氣key
}

所有數據的介面,都定義在了api.js文件中,此處沒什麼好說的,看官自行通過介面文檔查詢。介面均採用回調的方式,筆者並沒有封裝成Promise的方式,如果有興趣可自行更改。

// 引入config,為了後面的key
import config from '../uitl/config'
// 地圖key
const mapKey = config.MAP_API_KEY
// 和風天氣key
const weatherKey = config.WEATHER_API_KEY
// map url
const locationUrl = 'https://apis.map.qq.com/ws/geocoder/v1/'
//天氣url
const weatherUrl = 'https://free-api.heweather.net/s6/weather/forecast'
//24小時內 每小時
const everyhoursUrl = 'https://api.heweather.net/s6/weather/hourly'
// 一周內
const everyWeekUrl = 'https://api.heweather.net/s6/weather/forecast'
//空氣質量
const airQualityUrl = 'https://api.heweather.net/s6/air/now'
// 實況天氣
const weatherLive = 'https://api.heweather.net/s6/weather/now'
// 生活指數
const lifeStyle = 'https://api.heweather.net/s6/weather/lifestyle'
// 根據當前位置的坐標反得到當前位置的詳細信息
// lat,lon 為經緯度坐標
export const getPosition = (lat, lon, success = {}, fail = {}) => {
  return wx.request({
    url: locationUrl,
    header: {
      'Content-Type': 'application/json'
    },
    data: {
      location: `${lat},${lon}`,
      key: mapKey,
      get_poi: 0
    },
    success,
    fail
  })
}
// 根據location得到天氣信息
// lat,lon 為經緯度坐標
export const getWeaterInfo = (lat, lon, success = {}, fail = {}) => {
  return wx.request({
    url: weatherUrl,
    header: {
      'Content-Type': 'application/json'
    },
    data: {
      location: `${lat},${lon}`,
      lang: 'zh',
      unit: 'm',
      key: weatherKey
    },
    success,
    fail
  })
}
// 根據location信息得到24小逐小時天氣情況
// lat,lon 為經緯度坐標
export const getEveryHoursWeather = (lat, lon, success = {}, fail = {}) => {
  return wx.request({
    url: everyhoursUrl,
    header: {
      'Content-Type': 'application/json'
    },
    data: {
      location: `${lat},${lon}`,
      lang: 'zh',
      unit: 'm',
      key: weatherKey
    },
    success,
    fail
  })
}
...
... // 其他介面類似
...
}

3.實現邏輯(業務代碼)

3.1 流程

首先,當初次載入頁面時,大體流程為首先通過定位獲取位置,然後通過位置信息去得到我們需要的每一項天氣信息,最後將天氣信息渲染後頁面中相應的位置
具體流程

  • 獲取位置經緯度
  • 通過經緯度逆向獲得位置信息
  • 通過位置信息獲取天氣信息
    • 獲取實時天氣信息
      • 判斷是否為白天和晚上(改變頁面背景)--該小程式中定義早上6點到晚上18點為淺色背景,其他時間為深色背景
      • 判斷當前天氣的情況(雨或雪的大小),在實況天氣界面中通過canvas模擬雨雪的動畫
    • 獲取24小時天氣信息
    • 獲取一星期的天氣信息
    • 獲取生活指數信息

      當通過手動改變位置信息時,按順序重覆執行以上步驟

      3.2 獲取經緯度以及逆向出位置信息

      通過wx.getLocation原生方法獲取經緯度信息,在經過騰訊地圖api通過經緯度逆向獲取到相應的位置信息,對於這個項目來說獲取位置信息是最重要的信息,故我們希望在頁面一載入的時候就執行方法獲取,然後『onLoad』方法可以幫助我們解決,這個方法就是小程式的生命周期函數--監聽頁面載入,此方法會在頁面剛載入的時候(document文檔結構渲染完成後)執行。

      小程式頁面(Page)的生命周期函數:

name type functional
onLoad 函數 監聽頁面載入
onReady 函數 監聽頁面初次渲染完成
onShow 函數 監聽頁面顯示
onHide 函數 監聽頁面隱藏
onUnload 函數 監聽頁面卸載

以下為獲取位置信息代碼:

    // onLoad
    onLoad: function () {
        ...
        ...
        this.getPositon() // 調用獲取位置信息
    }
    // 原生方法獲取經緯度信息
    getPosition: function () {
        wx.getLocation({
            type: 'gcj02',
            success: this.updateLocation, // 成功會掉  updataLocation 方法為更新位置
            fail: err => {
                console.log(err)
            }
        })
    }
    // 更新位置信息
    updateLocation: function(res) {
        ...
        ...
        let {latitude: x,longitude: y,name} = res;
        let data = {
            location: {
                x,
                y,
                name: name || '北京市'
            },
            ...
            ...
        };
        this.setData(data); // 設置page中data對象中的屬性
        // 通過經緯度逆向獲得位置信息
        this.getLocation(x, y, name);
  }
  // 逆向獲取位置信息
  getLocation: function(lat, lon, name) {
    wx.showLoading({
      title: "定位中",
      mask: true
    })
    // 騰訊地圖api介面
    getPosition(lat, lon, (res) => {
        if (res.statusCode == 200) {
            let response = res.data.result
            let addr = response.formatted_addresses.recommend || response.rough
            this.setData({
                position: addr // 賦值給 data對象中的相應屬性
            })
            wx.hideLoading()
            this.getData(lat, lon);
        }
        }, (err => {
        console.log(err)
        wx.hideLoading()
        }))
  },
    // 當用戶點擊顯示定位處的view時,會調用原生的chooseLocation方法,內部調用選擇位置頁面
    chooseLocation: function() {
        wx.chooseLocation({
            success: res => {
                let {latitude,longitude} = res
                let {x,y} = this.data.location
                if (latitude == x && longitude == y) {

                } else {
                    this.updateLocation(res)
                }
            }
        })
    },
setData方法

上面代碼中兩次用到了setData方法,該方法接受一個對象,對象中的屬性為需要改變的數據,同時接受一個callback函數,用於通過改變數據更新頁面渲染完成之後的回調。我們來看看data的作用。

    page({
        data: {
            backgroundColor:'red',
            fontSize: '20',
            ...
            ...
        }
    })

在page中,data中的屬性是連接邏輯層視圖層的一個橋梁,也就是說我們可以通過js代碼的邏輯來控制data中的屬性的值,而頁面中的一部分顯示內容是根據data中的屬性的值而變化。這也就是我們所說的mvvm模型,我們只需把重心放在js邏輯層,而無需去頻繁的手動的操作視圖層。瞭解了data的作用,再來說setData,setData就是在js邏輯層中去改變和設置data中的屬性的值,從而使頁面得到響應。

    ...
    this.setData({
        backgroundColor: 'green' // 改變背景顏色屬性,視圖中以來此屬性的會將顏色變成綠色
    })
    ...

註意:

  • 直接修改this.data的值,而不是通過調用this.setData()方法,是無法成功改變頁面的狀態的
  • 僅僅支持JSON化的數據(key:value)
  • 單詞設置的值不能超過1024K,所以使用的時候儘量不要一次設置過多的數據
  • 不要把data中的任何一項value值設置成undefined,否則這一項將不能被設置,也可能會有其他問題
  • 不要頻繁的去調用this.setData()方法去設置同一個值或者多個值,比如通過在迴圈中調用this.setData(),這樣會導致性能損耗

3.3 獲取天氣

通過上面獲得到的位置信息,用來調用相應的介面獲得當前位置的天氣。方法介面已在前面封裝好,直接調用然後通過對response進行過濾或者重組等來滿足當前的應用,最後通過this.setData()方法去更新數據是頁面得到響應。

  • getWeather(lat, lon) // lat, lon 為當前位置的經緯度
  • getAir(lat, lon)
  • getHourWeather(lat, lon)
  • getWeatherForWeek(lat, lon)
  • getLifeIndex(lat, lon)

以上方法不在一一列舉其中數據處理的過程,可自行查看源碼 詳見 蝸牛小天氣 源碼

關於canvas畫出模擬雨和雪的粒子動畫效果

粒子動畫在現在越來越多的項目中被用到。從靜態到動態最後再到模擬效果更好的視覺體驗,也是人們在視覺上追求極致的體驗。我們通過粒子,也就是通過點和線,來模擬出雨和雪的效果。通過小程式中的canvas畫布來畫出我們想要的效果。
實現原理:

  • 首先我們通過點和線來模擬雨滴下落和雪花飄落
  • 我們通過在同一時間同一塊區域(也就是此小程式頁面中實況天氣的區域)中雨滴或雪花的多少來表示大小
  • 構造一個總的Weather基類,來設置畫布的width,height,以及雨滴或雪花的數量,同時會有兩個Start和Stop方法(也就是開始和停止方法)
  • 構造一個Rain類和一個Snow類,都繼承自Weather類,Rain和Snow都有自己私有的 _init(初始化), _drawing(畫), _update(更新畫布)三個方法來控制Rain和Snow的動作

Weather類

Weather類是一個基類,主要處理畫布的一些信息,例如width,height,定時器,以及當前動畫的狀態(status)等

    const STOP_ANIMATION = 'stop'
    const START_ANIMATION = 'start'

    class Weather {
        constructor(context, width, height, option = {}) {
            this.opt = option || {}
            this.context = context
            this.timer = null
            this.status = STOP_ANIMATION
            this.width = width
            this.height = height
            this._init()
        }
        // 實例調用此方法,開始在畫布上畫
        start() {
            if(this.status !== START_ANIMATION) {
                this.status = START_ANIMATION
                this.timer = setInterval(() => {
                    this._drawing()
                }, 30)
            return this
            }
        }
        stop() {
            this.status = STOP_ANIMATION
            clearInterval(this.timer)
            this.timer = null
            return this
        }
    }

    export default Weather

Rain類

Rain類繼承自Weather類,通過_init方法和父類中畫布參數,以及option參數中的counts(雨滴數量)來初始化。

import Weather from './Weather.js'
class Rain extends Weather {
    // 初始化
  _init() {
    this.context.setLineWidth(2)
    this.context.setLineCap('round')
    let height = this.height
    let width = this.width
    let counts = this.opt.counts || 100
    let speedCoefficient = this.opt.speedCoefficient
    let speed = speedCoefficient * height
    this.animationArray = []
    let arr = this.animationArray

    for (let i = 0; i < counts; i++) {
      let d = {
        x: Math.random() * width,
        y: Math.random() * height,
        len: 2 * Math.random(),
        xs: -1,
        ys: 10 * Math.random() + speed,
        color: 'rgba(255,255,255,0.1)'
      }
      arr.push(d)
    }
  }
 // 開始畫
  _drawing() {
    let arr = this.animationArray
    let ctx = this.context
    ctx.clearRect(0, 0, this.width, this.height)
    for (let i = 0; i < arr.length; i++) {
      let s = arr[i]
      ctx.beginPath()
      ctx.moveTo(s.x, s.y)
      ctx.lineTo(s.x + s.len * s.xs, s.y + s.len * s.ys)
      ctx.setStrokeStyle(s.color)
      ctx.stroke()
    }
    ctx.draw()
    return this.update()
  }
// 更新畫布
  update() {
    let width = this.width
    let height = this.height
    let arr = this.animationArray
    for (let i = 0; i < arr.length; i++) {
      let s = arr[i]
      s.x = s.x + s.xs
      s.y = s.y + s.ys
      if (s.x > width || s.y > height) {
        s.x = Math.random() * width
        s.y = -10
      }
    }
  }
}

export default Rain

Snow類

Snow類繼承自Weather類,通過_init方法和父類中畫布參數,以及option參數中的counts(雪花數量)來初始化。

import Weather from './Weather.js'
class Snow extends Weather {
    // 初始化
  _init() {
    let {
      width,
      height
    } = this
    console.log(width)
    let colors = this.opt.colors || ['#ccc', '#eee', '#fff', '#ddd']
    let counts = this.opt.counts || 100

    let speedCoefficient = this.opt.speedCoefficient || 0.03
    let speed = speedCoefficient * height * 0.15

    let radius = this.opt.radius || 2
    this.animationArray = []
    let arr = this.animationArray

    for (let i = 0; i < counts; i++) {
      arr.push({
        x: Math.random() * width,
        y: Math.random() * height,
        ox: Math.random() * width,
        ys: Math.random() + speed,
        r: Math.floor(Math.random() * (radius + 0.5) + 0.5),
        color: colors[Math.floor(Math.random() * colors.length)],
        rs: Math.random() * 80
      })
    }
    console.log(arr)
  }
  // 開始畫
  _drawing() {
    let arr = this.animationArray
    let context = this.context
    context.clearRect(0, 0, this.width, this.height)
    for (let i = 0; i < arr.length; i++) {
      let {
        x,
        y,
        r,
        color
      } = arr[i]
      context.beginPath()
      context.arc(x, y, r, 0, Math.PI * 2, false)
      context.setFillStyle(color)
      context.fill()
      context.closePath()
    }

    context.draw()
    this._update()
  }
  // 更新畫布
  _update() {
    let {
      width,
      height
    } = this
    let arr = this.animationArray
    let v = this.opt.speedCoefficient / 10
    for (let i = 0; i < arr.length; i++) {
      let p = arr[i]
      let {
        ox,
        ys
      } = p
      p.rs += v
      p.x = ox + Math.cos(p.rs) * width / 2
      p.y += ys
      if (p.x > width || p.y > height) {
        p.x = Math.random() * width![](https://img2018.cnblogs.com/blog/1114695/201903/1114695-20190322103830275-1850899412.png)

        p.y = -10
      }
    }
  }
}

export default Snow

結束!!!


到此,蝸牛小天氣就開發完成了,希望對各位有幫助。
希望在閱讀的同時如果感覺對各位有幫助,還請看官別忘了給你大大的贊

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文地址:http://wushaobin.top/2019/03/15/webpackPlugin/ 什麼是Plugin? 在 "Webpack學習-工作原理(上)" 一文中我們就已經介紹了 的基本概念,同時知道了webpack其實很像一條生產線,要經過一系列處理流程後才能將源文件轉換成我們理想的 ...
  • 秒轉換成年月日時分秒 秒轉換成年月日時分秒 複製文本 複製文本 <script type="text/javascript"> function copy() { var url=document.getElementById("textID"); // 獲取要操作的DOM Url2.select( ...
  • import axios from 'axios' let CdnPath = {} CdnPath.install = function (Vue, options) { Vue.prototype.$_cdnDomain = function () { if (process.env.NODE_... ...
  • HTML基本結構: 選擇圖片 預覽圖: 立即提交 Java... ...
  • 前端路由 看到這裡可能有朋友有疑惑了,前端也有路由嗎?這些難道不應該是在後端部分操作的嗎?確實是這樣,但是現在前後端分離後,加上現在的前端框架的實用性,為的就是均衡前後端的工作量,所以在前端也有了路由,減輕了伺服器對這方面的判斷,在前端做好路由分發之後,後端就只需要寫API介面了,更著重於數據... ...
  • 鏈式編程 多行代碼合併成一行代碼,前提要認清此行代碼返回的是不是對象.是對象才能進行鏈式編程 .html(‘val’).text(‘val’).css()鏈式編程,隱式迭代 鏈式編程註意:$(‘div’).html(‘設置值’).val(‘設置值’);這樣可以,但是$(‘div’).html().t ...
  • 第二章 1.如果我們在控制臺中執行下列語句,結果分別是什麼?為什麼? 2.執行下麵的語句後,v 的值會是什麼? var v = v || 10; 如果將v 分別設置為100、0、null,結果又將是什麼? 100, 10, 10 3.編寫一個列印乘法口訣表的腳本程式。提示:使用嵌套迴圈來實現。 第三 ...
  • walkDOM getElementsByClassName 第六章 6.5 判斷是不是數組 寫一個Reduce 第七章 正則表達式 7.1 匹配url的正則 匹配數字的reg ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...