أضف المدونات والوثائق والصفحات الثابتة الأخرى إلى تطبيقات Phoenix. تتكامل هذه المكتبة بسلاسة مع جهاز التوجيه الخاص بك وتأتي مع دعم مدمج لعرض تخفيض السعر مع المادة الأمامية، وتمييز بناء الجملة، والتخزين المؤقت لوقت الترجمة، والمزيد.
def deps do
[
{ :phoenix_pages , "~> 0.1" }
]
end
الطريقة الموصى بها للتثبيت في تطبيق Phoenix الخاص بك هي إضافة هذا إلى وظيفة router
الخاص بك في lib/myapp_web.ex
، مع استبدال myapp
باسم التطبيق الخاص بك:
def router do
quote do
use Phoenix.Router , helpers: false
use PhoenixPages , otp_app: :myapp
# ...
end
end
يمكنك الآن إضافة مسار جديد باستخدام الماكرو pages/4
:
scope "/" , MyAppWeb do
pipe_through :browser
get "/" , PageController , :home
pages "/:page" , PageController , :show , from: "priv/pages/**/*.md"
end
سيؤدي هذا إلى قراءة جميع ملفات تخفيض السعر من priv/pages
وإنشاء مسار GET جديد لكل ملف. سيتم استبدال مقطع :page
بالمسار واسم الملف (بدون الامتداد) بالنسبة للدليل الأساسي (راجع تعريف المسارات).
ستحتاج أيضًا إلى إضافة معالج :show
إلى lib/myapp_web/controllers/page_controller.ex
:
defmodule MyAppWeb.PageController do
use MyAppWeb , :controller
# ...
def show ( conn , _params ) do
render ( conn , "show.html" )
end
end
وأخيرًا، قم بإضافة قالب على lib/myapp_web/controllers/page_html/show.html.heex
. سيكون تخفيض السعر المعروض للصفحة متاحًا في تعيين inner_content
:
< main >
<%= @inner_content % >
</ main >
هذا كل شيء! حاول الآن إنشاء ملف على priv/pages/hello.md
وزيارة /hello
.
لمنع mix format
من إضافة أقواس إلى ماكرو pages
المشابه لوحدات ماكرو Phoenix Router الأخرى، أضف :phoenix_pages
إلى .formatter.exs
:
[
import_deps: [ :ecto , :ecto_sql , :phoenix , :phoenix_pages ]
]
يسمح Frontmatter بتضمين المتغيرات الخاصة بالصفحة في الجزء العلوي من ملف تخفيض السعر باستخدام تنسيق YAML. إذا كنت تقوم بتعيين متغيرات المادة الأمامية (وهو أمر اختياري)، فيجب أن تكون أول شيء في الملف ويجب تعيينها بين الخطوط الثلاثية المتقطعة:
---
title : Hello World
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
لتحديد قيم الواجهة المتوقعة في كل صفحة، اضبط خيار attrs
:
pages "/:page" , PageController , :show ,
from: "priv/pages/**/*.md" ,
attrs: [ :title , author: nil ]
سيتم اعتبار قيم Atom مطلوبة، وسيتم ظهور خطأ في الترجمة إذا كانت مفقودة من أي من الصفحات. يجب أن تأتي القيم الأساسية في آخر القائمة، وسيتم اعتبارها اختيارية من خلال تحديد قيمة افتراضية. سيتم تجاهل أي قيم أمامية غير محددة في قائمة السمات بصمت.
ستكون قيم السمات الصالحة متاحة في التعيينات:
< main >
< h1 > <%= @title % > </ h1 >
< h2 :if = {@author} > <%= @author % > </ h2 >
<%= @inner_content % >
</ main >
تستخدم Phoenix Pages مشروع الماكياج لتسليط الضوء على بناء الجملة. للتمكين، قم بإضافة معجم للغتك (لغاتك) المحددة إلى تبعيات المشروع. سوف تلتقط Phoenix Pages التبعية الجديدة وتبدأ في تمييز كتل التعليمات البرمجية الخاصة بك دون أي تكوين إضافي. لا يتم تضمين أي معجم بشكل افتراضي.
`{:makeup_c, "~> 0.0"}`
`{:makeup_diff, "~> 0.0"}`
`{:makeup_elixir, "~> 0.0"}`
`{:makeup_erlang, "~> 0.0"}`
`{:makeup_graphql, "~> 0.0"}`
`{:makeup_eex, "~> 0.0"}`
`{:makeup_html, "~> 0.0"}`
`{:makeup_js, "~> 0.0"}`
`{:makeup_json, "~> 0.0"}`
`{:makeup_rust, "~> 0.0"}`
`{:makeup_sql, "~> 0.0"}`
إذا لم تكن اللغة التي تختارها مدعومة، ففكر في كتابة معجم مكياج جديد للمساهمة في المجتمع. بخلاف ذلك، يمكنك استخدام أداة تمييز بناء الجملة المستندة إلى JS، مثل Highlight.js عن طريق تعيين code_class_prefix: "language-"
و syntax_highlighting: false
في render_options
.
بعد ذلك، قم باستيراد سمة مدرجة أدناه في حزمة CSS الخاصة بك. تعتمد تفاصيل القيام بذلك بشكل كبير على تكوين CSS الخاص بك، ولكن تم تضمين بعض الأمثلة أدناه. في معظم الحالات، ستحتاج إلى استيراد phoenix_pages/css/monokai.css
(أو أي سمة تختارها) إلى حزمتك والتأكد من تضمين deps
كدليل بائع.
باستخدام مثبت ESBuild، أضف خيار env
إلى config/config.exs
:
config :esbuild ,
version: "0.17.18" ,
default: [
cd: Path . expand ( "../assets" , __DIR__ ) ,
env: % { "NODE_PATH" => Path . expand ( "../deps" , __DIR__ ) } ,
args: ~w ( --bundle --outdir=../priv/static/assets js/app.js )
]
ثم في app.js
:
import "phoenix_pages/css/monokai.css" ;
باستخدام مُثبت Sass، أضف علامة --load-path
إلى config/config.exs
:
config :dart_sass ,
version: "1.62.0" ,
default: [
cd: Path . expand ( "../assets" , __DIR__ ) ,
args: ~w ( --load-path=../deps css/app.scss ../priv/static/assets/app.css )
]
ثم في app.scss
:
@import " phoenix_pages/css/monokai " ;
قم بتثبيت البرنامج الإضافي postcss-import
كما هو موضح هنا وأضف ما يلي إلى assets/postcss.config.js
:
module . exports = {
plugins : {
"postcss-import" : { }
}
}
ثم في app.css
:
@import "../../deps/phoenix_pages/css/monokai" ;
لإنشاء صفحة فهرس تحتوي على روابط لجميع الصفحات الأخرى، قم بإنشاء مسار GET عادي واستخدم خيار id
بجانب get_pages/1
و get_pages!/1
في جهاز التوجيه الخاص بك:
get "/blog" , BlogController , :index
pages "/blog/:page" , BlogController , :show ,
id: :blog ,
from: "priv/blog/**/*.md" ,
attrs: [ :title , :author , :date ]
defmodule MyAppWeb.BlogController do
use MyAppWeb , :controller
def index ( conn , _params ) do
pages = MyAppWeb.Router . get_pages! ( :blog )
conn
|> assign ( :pages , pages )
|> render ( "index.html" )
end
def show ( conn , _params ) do
render ( conn , "show.html" )
end
end
<.link :for={page < - @pages} navigate = {page.path} >
<%= page.assigns.title % >
</.link>
تتم قراءة جميع ملفات الصفحة وتخزينها مؤقتًا أثناء التجميع، وبالتالي فإن وظائف get_pages
لن تقرأ فعليًا أي شيء من نظام الملفات - مما يجعلها عالية الأداء.
سيتم فرز الصفحات التي يتم إرجاعها من وظائف get_pages
حسب اسم الملف. إذا كنت تريد تحديد ترتيب مختلف أثناء الترجمة بدلاً من تحديده في وحدة التحكم عند كل تحميل للصفحة، فاستخدم خيار sort
:
pages "/blog/:page" , BlogController , :show ,
id: :blog ,
from: "priv/blog/**/*.md" ,
attrs: [ :title , :author , :date ] ,
sort: { :date , :desc }
يمكن تعريف أي قيمة سمة من المادة الأمامية على أنها قيمة الفرز.
عند تحديد مسار الصفحات، سيتم استبدال مقطع :page
لكل صفحة تم إنشاؤها أثناء التجميع بالقيم المشتقة من **
و *
. ويختلف هذا عن المقاطع الموجودة في المسارات العادية، والتي يتم تحليلها أثناء وقت التشغيل إلى سمة params
بوظيفة وحدة التحكم.
على سبيل المثال، لنفترض أن لديك بنية الملف التالية:
┌── priv/
│ ┌── pages/
│ │ ┌── foo.md
│ │ ├── bar/
│ │ │ ┌── baz.md
سيؤدي تحديد pages "/:page", from: "priv/pages/**/*.md"
في جهاز التوجيه الخاص بك إلى إنشاء طريقين: get "/foo"
والحصول get "/bar/baz"
. يمكنك أيضًا وضع مقطع :page
في مكان آخر في المسار، مثل /blog/:page
، وسيعمل كما هو متوقع عند إنشاء get "/blog/foo"
و get "/blog/bar/baz"
.
بالنسبة للسيناريوهات المعقدة، لديك خيار استخدام متغيرات مجموعة الالتقاط بدلاً من مقطع :page
:.
لنفترض أن لديك نفس بنية الملف المذكورة أعلاه، لكنك لا تريد أن يكون مسار baz
متداخلاً ضمن /bar
. يمكنك تحديد pages "/$2", from: "priv/pages/**/*.md"
باستخدام $2
بدلاً من :page
. سيؤدي هذا إلى إنشاء طريقين: get "/foo"
get "/bar"
.
ستحتوي متغيرات مجموعة الالتقاط على قيمة القطع **
و *
بالترتيب، بدءًا من $1
. ضع في اعتبارك أن **
سيطابق جميع الملفات وصفر أو أكثر من الدلائل والأدلة الفرعية، وسيطابق *
أي عدد من الأحرف حتى نهاية اسم الملف، أو النقطة التالية، أو الشرطة المائلة التالية.
لمزيد من المعلومات حول أنماط أحرف البدل، راجع Path.wildcard/2.
بالإضافة إلى خيارات تخفيض السعر القابلة للتخصيص، يدعم عرض تخفيض السعر أيضًا سمات IAL بشكل افتراضي. بمعنى أنه يمكنك إضافة سمات HTML إلى أي عنصر على مستوى الكتلة باستخدام بناء الجملة {:attr}
.
على سبيل المثال، لإنشاء مخرجات معروضة لـ <h1 class="foobar">Header</h1>
:
# Header{:.foobar}
يمكن أن تكون السمات واحدة مما يلي:
{:#id}
لتحديد معرف{:.className}
لتحديد اسم الفئة{:name=value}
أو {:name="value"}
أو {:name='value'}
لتحديد أي سمة أخرى لتحديد سمات متعددة، افصل بينها بمسافات: {:#id name=value}
.
إذا قمت بإضافة صفحات أو إزالتها أو تغييرها أثناء تشغيل mix phx.server
، فسيتم استبدالها تلقائيًا في ذاكرة التخزين المؤقت ولن يتعين عليك إعادة التشغيل حتى تدخل حيز التنفيذ. لإعادة التحميل المباشر عندما تتغير الصفحة، أضف إلى قائمة الأنماط الخاصة بتكوين نقطة النهاية في config/dev.exs
:
config :myapp , MyAppWeb.Endpoint ,
live_reload: [
patterns: [
# ...
~r " priv/pages/.*(md)$ " ,
# ...
]
]